public void injectEmailTemplate(
      final JavaType targetType, final JavaSymbolName fieldName, final boolean async) {
    Assert.notNull(targetType, "Java type required");
    Assert.notNull(fieldName, "Field name required");

    final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
    annotations.add(new AnnotationMetadataBuilder(AUTOWIRED));

    // Obtain the physical type and its mutable class details
    final String declaredByMetadataId = PhysicalTypeIdentifier.createIdentifier(targetType);
    ClassOrInterfaceTypeDetails existing = typeLocationService.findClassOrInterface(targetType);
    if (existing == null) {
      log.warning(
          "Aborting: Unable to find metadata for target type '"
              + targetType.getFullyQualifiedTypeName()
              + "'");
      return;
    }
    final ClassOrInterfaceTypeDetailsBuilder classOrInterfaceTypeDetailsBuilder =
        new ClassOrInterfaceTypeDetailsBuilder(existing);

    // Add the MailSender field
    final FieldMetadataBuilder mailSenderFieldBuilder =
        new FieldMetadataBuilder(
            declaredByMetadataId, PRIVATE_TRANSIENT, annotations, fieldName, MAIL_SENDER);
    classOrInterfaceTypeDetailsBuilder.addField(mailSenderFieldBuilder.build());

    // Add the "sendMessage" method
    classOrInterfaceTypeDetailsBuilder.addMethod(
        getSendMethod(fieldName, async, declaredByMetadataId, classOrInterfaceTypeDetailsBuilder));
    typeManagementService.createOrUpdateTypeOnDisk(classOrInterfaceTypeDetailsBuilder.build());
  }
  public void addEnumConstant(
      final String physicalTypeIdentifier, final JavaSymbolName constantName) {
    Assert.hasText(physicalTypeIdentifier, "Type identifier not provided");
    Assert.notNull(constantName, "Constant name required");

    // Obtain the physical type and itd mutable details
    PhysicalTypeMetadata ptm = (PhysicalTypeMetadata) metadataService.get(physicalTypeIdentifier);
    Assert.notNull(
        ptm,
        "Java source code unavailable for type "
            + PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
    PhysicalTypeDetails ptd = ptm.getMemberHoldingTypeDetails();
    Assert.notNull(
        ptd,
        "Java source code details unavailable for type "
            + PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
    ClassOrInterfaceTypeDetailsBuilder cidBuilder =
        new ClassOrInterfaceTypeDetailsBuilder((ClassOrInterfaceTypeDetails) ptd);

    // Ensure it's an enum
    Assert.isTrue(
        cidBuilder.getPhysicalTypeCategory() == PhysicalTypeCategory.ENUMERATION,
        PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier) + " is not an enum");

    cidBuilder.addEnumConstant(constantName);
    createOrUpdateTypeOnDisk(cidBuilder.build());
  }
  public List<JavaSymbolName> getFinders(
      MemberDetails memberDetails, String plural, int depth, Set<JavaSymbolName> exclusions) {
    Assert.notNull(memberDetails, "Member details required");
    Assert.hasText(plural, "Plural required");
    Assert.notNull(
        depth, "The depth of combinations used for finder signatures combinations required");
    Assert.notNull(exclusions, "Exclusions required");

    SortedSet<JavaSymbolName> finders = new TreeSet<JavaSymbolName>();

    List<FieldMetadata> fields = memberDetails.getFields();
    for (int i = 0; i < depth; i++) {
      SortedSet<JavaSymbolName> tempFinders = new TreeSet<JavaSymbolName>();
      for (FieldMetadata field : fields) {
        // Ignoring java.util.Map field types (see ROO-194)
        if (field == null || field.getFieldType().equals(new JavaType(Map.class.getName()))) {
          continue;
        }
        if (exclusions.contains(field.getFieldName())) {
          continue;
        }
        if (i == 0) {
          tempFinders.addAll(createFinders(field, finders, "find" + plural + "By", true));
        } else {
          tempFinders.addAll(createFinders(field, finders, "And", false));
          tempFinders.addAll(createFinders(field, finders, "Or", false));
        }
      }
      finders.addAll(tempFinders);
    }

    return Collections.unmodifiableList(new ArrayList<JavaSymbolName>(finders));
  }
  public String getIdentifier(final LogicalPath logicalPath, final String relativePath) {
    Assert.notNull(logicalPath, "Path required");
    Assert.notNull(relativePath, "Relative path cannot be null, although it can be empty");

    String initialPath = FileUtils.getCanonicalPath(getPath(logicalPath));
    initialPath = FileUtils.ensureTrailingSeparator(initialPath);
    return initialPath + FileUtils.removeLeadingAndTrailingSeparators(relativePath);
  }
  /**
   * Constructor
   *
   * @param metadataId (required)
   * @param aspectName (required)
   * @param governorPhysicalTypeMetadata (required)
   * @param parent can be <code>null</code>
   * @param projectMetadata (required)
   * @param crudAnnotationValues the CRUD-related annotation values (required)
   * @param plural the plural form of the entity (required)
   * @param identifierField the entity's identifier field (required)
   * @param entityName the JPA entity name (required)
   */
  public JpaActiveRecordMetadata(
      final String metadataId,
      final JavaType aspectName,
      final PhysicalTypeMetadata governorPhysicalTypeMetadata,
      final JpaActiveRecordMetadata parent,
      final JpaCrudAnnotationValues crudAnnotationValues,
      final String plural,
      final FieldMetadata identifierField,
      final String entityName,
      final boolean isGaeEnabled) {
    super(metadataId, aspectName, governorPhysicalTypeMetadata);
    Assert.isTrue(
        isValid(metadataId),
        "Metadata identification string '" + metadataId + "' does not appear to be a valid");
    Assert.notNull(crudAnnotationValues, "CRUD-related annotation values required");
    Assert.notNull(identifierField, "Identifier required for '" + metadataId + "'");
    Assert.hasText(entityName, "Entity name required for '" + metadataId + "'");
    Assert.hasText(plural, "Plural required for '" + metadataId + "'");

    if (!isValid()) {
      return;
    }

    this.crudAnnotationValues = crudAnnotationValues;
    this.entityName = entityName;
    this.identifierField = identifierField;
    this.isGaeEnabled = isGaeEnabled;
    this.parent = parent;
    this.plural = StringUtils.capitalize(plural);

    // Determine the entity's "entityManager" field, which is guaranteed to be accessible to the
    // ITD.
    builder.addField(getEntityManagerField());

    // Add helper methods
    builder.addMethod(getPersistMethod());
    builder.addMethod(getRemoveMethod());
    builder.addMethod(getFlushMethod());
    builder.addMethod(getClearMethod());
    builder.addMethod(getMergeMethod());

    // Add static methods
    builder.addMethod(getEntityManagerMethod());
    builder.addMethod(getCountMethod());
    builder.addMethod(getFindAllMethod());
    builder.addMethod(getFindMethod());
    builder.addMethod(getFindEntriesMethod());

    builder.putCustomData(CustomDataKeys.DYNAMIC_FINDER_NAMES, getDynamicFinders());

    // Create a representation of the desired output ITD
    itdTypeDetails = builder.build();
  }
Beispiel #6
0
  public JsonMetadata(
      String identifier,
      JavaType aspectName,
      PhysicalTypeMetadata governorPhysicalTypeMetadata,
      String typeNamePlural,
      JsonAnnotationValues annotationValues) {
    super(identifier, aspectName, governorPhysicalTypeMetadata);
    Assert.notNull(annotationValues, "Annotation values required");
    Assert.hasText(typeNamePlural, "Plural of the target type required");
    Assert.isTrue(
        isValid(identifier),
        "Metadata identification string '" + identifier + "' does not appear to be a valid");

    if (!isValid()) {
      return;
    }

    this.annotationValues = annotationValues;
    this.typeNamePlural = typeNamePlural;

    builder.addMethod(getToJsonMethod());
    builder.addMethod(getFromJsonMethod());
    builder.addMethod(getToJsonArrayMethod());
    builder.addMethod(getFromJsonArrayMethod());

    // Create a representation of the desired output ITD
    itdTypeDetails = builder.build();
  }
Beispiel #7
0
 /**
  * Returns the portion of the child identifier that is relative to the parent {@link FileDetails}
  * instance. Note that this instance must be the parent.
  *
  * <p>If an empty string is returned from this method, it denotes the child was actually the same
  * identifier as the parent.
  *
  * @param childCanonicalPath the confirmed child of this instance (required; use canonical path)
  * @return the relative path within the parent instance (never null)
  */
 public String getRelativeSegment(final String childCanonicalPath) {
   Assert.notNull(childCanonicalPath, "Child identifier is required");
   Assert.isTrue(
       isParentOf(childCanonicalPath),
       "Identifier '" + childCanonicalPath + "' is not a child of '" + this + "'");
   return childCanonicalPath.substring(getCanonicalPath().length());
 }
 public JavaType getItdJavaType(final ItdMetadataProvider metadataProvider) {
   Assert.notNull(metadataProvider, "Metadata provider required");
   return new JavaType(
       PhysicalTypeIdentifier.getJavaType(getId()).getFullyQualifiedTypeName()
           + "_Roo_"
           + metadataProvider.getItdUniquenessFilenameSuffix());
 }
  /**
   * Constructor
   *
   * @param identifier
   * @param aspectName
   * @param governorPhysicalTypeMetadata
   * @param locatedAccessors
   */
  public ToStringMetadata(
      String identifier,
      JavaType aspectName,
      PhysicalTypeMetadata governorPhysicalTypeMetadata,
      List<MethodMetadata> locatedAccessors) {
    super(identifier, aspectName, governorPhysicalTypeMetadata);
    Assert.isTrue(
        isValid(identifier),
        "Metadata identification string '" + identifier + "' does not appear to be a valid");
    Assert.notNull(locatedAccessors, "Public accessors required");

    this.locatedAccessors = locatedAccessors;

    // Process values from the annotation, if present
    AnnotationMetadata annotation = governorTypeDetails.getAnnotation(RooJavaType.ROO_TO_STRING);
    if (annotation != null) {
      AutoPopulationUtils.populate(this, annotation);
    }

    // Generate the toString
    builder.addMethod(getToStringMethod());

    // Create a representation of the desired output ITD
    itdTypeDetails = builder.build();
  }
 public GwtProxyProperty(
     final JavaPackage topLevelPackage,
     final ClassOrInterfaceTypeDetails ptmd,
     final JavaType type) {
   Assert.notNull(type, "Type required");
   this.topLevelPackage = topLevelPackage;
   this.ptmd = ptmd;
   this.type = type;
 }
  public void addField(final FieldMetadata field) {
    Assert.notNull(field, "Field metadata not provided");

    // Obtain the physical type and ITD mutable details
    PhysicalTypeMetadata ptm =
        (PhysicalTypeMetadata) metadataService.get(field.getDeclaredByMetadataId());
    Assert.notNull(
        ptm,
        "Java source code unavailable for type "
            + PhysicalTypeIdentifier.getFriendlyName(field.getDeclaredByMetadataId()));
    PhysicalTypeDetails ptd = ptm.getMemberHoldingTypeDetails();
    Assert.notNull(
        ptd,
        "Java source code details unavailable for type "
            + PhysicalTypeIdentifier.getFriendlyName(field.getDeclaredByMetadataId()));
    ClassOrInterfaceTypeDetailsBuilder cidBuilder =
        new ClassOrInterfaceTypeDetailsBuilder((ClassOrInterfaceTypeDetails) ptd);

    // Automatically add JSR 303 (Bean Validation API) support if there is
    // no current JSR 303 support but a JSR 303 annotation is present
    boolean jsr303Required = false;
    for (AnnotationMetadata annotation : field.getAnnotations()) {
      if (annotation
          .getAnnotationType()
          .getFullyQualifiedTypeName()
          .startsWith("javax.validation")) {
        jsr303Required = true;
        break;
      }
    }

    LogicalPath path = PhysicalTypeIdentifier.getPath(cidBuilder.getDeclaredByMetadataId());

    if (jsr303Required) {
      // It's more likely the version below represents a later version
      // than any specified in the user's own dependency list
      projectOperations.addDependency(
          path.getModule(), "javax.validation", "validation-api", "1.0.0.GA");
    }
    cidBuilder.addField(field);
    createOrUpdateTypeOnDisk(cidBuilder.build());
  }
 /**
  * Returns the {@link JavaType} from the specified {@link MemberDetails} object;
  *
  * <p>If the found type is abstract the next {@link MemberHoldingTypeDetails} is searched.
  *
  * @param memberDetails the {@link MemberDetails} to search (required)
  * @return the first non-abstract JavaType, or null if not found
  */
 private JavaType getConcreteJavaType(MemberDetails memberDetails) {
   Assert.notNull(memberDetails, "Member details required");
   JavaType javaType = null;
   for (MemberHoldingTypeDetails memberHoldingTypeDetails : memberDetails.getDetails()) {
     if (Modifier.isAbstract(memberHoldingTypeDetails.getModifier())) {
       continue;
     }
     javaType = memberHoldingTypeDetails.getName();
   }
   return javaType;
 }
 public String getItdCanonicalPath(final ItdMetadataProvider metadataProvider) {
   Assert.notNull(metadataProvider, "Metadata provider required");
   final int dropFrom = this.physicalLocationCanonicalPath.lastIndexOf(".java");
   Assert.isTrue(
       dropFrom > -1,
       "Unexpected governor filename format '" + this.physicalLocationCanonicalPath + "'");
   return this.physicalLocationCanonicalPath.substring(0, dropFrom)
       + "_Roo_"
       + metadataProvider.getItdUniquenessFilenameSuffix()
       + ".aj";
 }
  public QueryHolder getQueryHolder(
      MemberDetails memberDetails, JavaSymbolName finderName, String plural, String entityName) {
    Assert.notNull(memberDetails, "Member details required");
    Assert.notNull(finderName, "Finder name required");
    Assert.hasText(plural, "Plural required");

    List<Token> tokens;
    try {
      tokens = tokenize(memberDetails, finderName, plural);
    } catch (FinderFieldTokenMissingException e) {
      return null;
    } catch (InvalidFinderException e) {
      return null;
    }

    String simpleTypeName = getConcreteJavaType(memberDetails).getSimpleTypeName();
    String jpaQuery = getJpaQuery(tokens, simpleTypeName, finderName, plural, entityName);
    List<JavaType> parameterTypes = getParameterTypes(tokens, finderName, plural);
    List<JavaSymbolName> parameterNames = getParameterNames(tokens, finderName, plural);
    return new QueryHolder(jpaQuery, parameterTypes, parameterNames, tokens);
  }
 /**
  * Constructor
  *
  * @param annotationType the type of annotation for which these are the metadata (required)
  * @param attributeValues the given annotation's values; can be <code>null</code>
  */
 DefaultAnnotationMetadata(
     final JavaType annotationType, final List<AnnotationAttributeValue<?>> attributeValues) {
   Assert.notNull(annotationType, "Annotation type required");
   this.annotationType = annotationType;
   this.attributes = new ArrayList<AnnotationAttributeValue<?>>();
   this.attributeMap = new HashMap<JavaSymbolName, AnnotationAttributeValue<?>>();
   if (attributeValues != null) {
     this.attributes.addAll(attributeValues);
     for (final AnnotationAttributeValue<?> value : attributeValues) {
       this.attributeMap.put(value.getName(), value);
     }
   }
 }
 /**
  * Constructor
  *
  * @param metadataId the ID to assign this {@link org.springframework.roo.metadata.MetadataItem}
  *     (must satisfy {@link PhysicalTypeIdentifier#isValid(String)})
  * @param physicalLocationCanonicalPath the canonical path of the file containing this Java type
  *     (required)
  * @param memberHoldingTypeDetails the members of this type (required)
  */
 public DefaultPhysicalTypeMetadata(
     final String metadataId,
     final String physicalLocationCanonicalPath,
     final MemberHoldingTypeDetails memberHoldingTypeDetails) {
   super(metadataId);
   Assert.isTrue(
       PhysicalTypeIdentifier.isValid(metadataId),
       "Metadata id '" + metadataId + "' is not a valid physical type identifier");
   Assert.hasText(physicalLocationCanonicalPath, "Physical location canonical path required");
   Assert.notNull(memberHoldingTypeDetails, "Member holding type details required");
   this.memberHoldingTypeDetails = memberHoldingTypeDetails;
   this.physicalLocationCanonicalPath = physicalLocationCanonicalPath;
 }
 public ClassOrInterfaceTypeDetails getTemplateDetails(
     final TemplateDataDictionary dataDictionary,
     final String templateFile,
     final JavaType templateType,
     final String moduleName) {
   try {
     TemplateLoader templateLoader = TemplateResourceLoader.create();
     Template template = templateLoader.getTemplate(templateFile);
     Assert.notNull(template, "Tenmplate required for '" + templateFile + "'");
     String templateContents = template.renderToString(dataDictionary);
     String templateId =
         PhysicalTypeIdentifier.createIdentifier(
             templateType, LogicalPath.getInstance(Path.SRC_MAIN_JAVA, moduleName));
     return typeParsingService.getTypeFromString(templateContents, templateId, templateType);
   } catch (Exception e) {
     throw new IllegalStateException(e);
   }
 }
  public Database refreshDatabase(
      final Set<Schema> schemas,
      final boolean view,
      final Set<String> includeTables,
      final Set<String> excludeTables) {
    Assert.notNull(schemas, "Schemas required");

    Connection connection = null;
    try {
      connection = getConnection(true);
      DatabaseIntrospector introspector =
          new DatabaseIntrospector(connection, schemas, view, includeTables, excludeTables);
      Database database = introspector.createDatabase();
      cacheDatabase(database);
      return database;
    } catch (Exception e) {
      throw new IllegalStateException(e);
    } finally {
      connectionProvider.closeConnection(connection);
    }
  }
 /**
  * Locates the first {@link PhysicalPath} which can be construed as a parent of the presented
  * identifier.
  *
  * @param identifier to locate the parent of (required)
  * @return the first matching parent, or null if not found
  */
 protected PhysicalPath getApplicablePhysicalPath(final String identifier) {
   Assert.notNull(identifier, "Identifier required");
   PhysicalPath physicalPath = null;
   int longest = 0;
   for (final Pom pom : pomManagementService.getPoms()) {
     if (removeTrailingSeparator(identifier).startsWith(removeTrailingSeparator(pom.getRoot()))
         && removeTrailingSeparator(pom.getRoot()).length() > longest) {
       longest = removeTrailingSeparator(pom.getRoot()).length();
       int nextLongest = 0;
       for (final PhysicalPath thisPhysicalPath : pom.getPhysicalPaths()) {
         final String possibleParent =
             new FileDetails(thisPhysicalPath.getLocation(), null).getCanonicalPath();
         if (removeTrailingSeparator(identifier).startsWith(possibleParent)
             && possibleParent.length() > nextLongest) {
           nextLongest = possibleParent.length();
           physicalPath = thisPhysicalPath;
         }
       }
     }
   }
   return physicalPath;
 }
Beispiel #20
0
 /**
  * Constructor
  *
  * @param file the file for which these are the details (required)
  * @param lastModified the system clock in milliseconds when this file was last modified (can be
  *     <code>null</code>)
  */
 public FileDetails(final File file, final Long lastModified) {
   Assert.notNull(file, "File required");
   this.file = file;
   this.lastModified = lastModified;
 }
 public AnnotationAttributeValue<?> getAttribute(final JavaSymbolName attributeName) {
   Assert.notNull(attributeName, "Attribute name required");
   return attributeMap.get(attributeName);
 }
 /**
  * Removes a {@link JavaType} metadata trigger registration. If the type was never registered, the
  * method returns without an error.
  *
  * @param javaType to remove (required)
  */
 public void removeMetadataTrigger(final JavaType javaType) {
   Assert.notNull(javaType, "Java type required for metadata trigger deregistration");
   this.metadataTriggers.remove(javaType);
 }
  private MethodMetadata getDelegateMethod(
      final JavaSymbolName methodName, final String methodDelegateName) {
    // Method definition to find or build
    final JavaType[] parameterTypes = {};

    // Locate user-defined method
    final MethodMetadata userMethod = getGovernorMethod(methodName, parameterTypes);
    if (userMethod != null) {
      return userMethod;
    }

    // Create the method
    final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();

    final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();

    // Address non-injected entity manager field
    final MethodMetadata entityManagerMethod = getEntityManagerMethod();
    Assert.notNull(entityManagerMethod, "Entity manager method should not have returned null");

    // Use the getEntityManager() method to acquire an entity manager (the method will throw an
    // exception if it cannot be acquired)
    final String entityManagerFieldName = getEntityManagerField().getFieldName().getSymbolName();
    bodyBuilder.appendFormalLine(
        "if (this."
            + entityManagerFieldName
            + " == null) this."
            + entityManagerFieldName
            + " = "
            + entityManagerMethod.getMethodName().getSymbolName()
            + "();");

    JavaType returnType = JavaType.VOID_PRIMITIVE;
    if ("flush".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".flush();");
    } else if ("clear".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".clear();");
    } else if ("merge".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      returnType = new JavaType(destination.getSimpleTypeName());
      bodyBuilder.appendFormalLine(
          destination.getSimpleTypeName()
              + " merged = this."
              + entityManagerFieldName
              + ".merge(this);");
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".flush();");
      bodyBuilder.appendFormalLine("return merged;");
    } else if ("remove".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      bodyBuilder.appendFormalLine("if (this." + entityManagerFieldName + ".contains(this)) {");
      bodyBuilder.indent();
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".remove(this);");
      bodyBuilder.indentRemove();
      bodyBuilder.appendFormalLine("} else {");
      bodyBuilder.indent();
      bodyBuilder.appendFormalLine(
          destination.getSimpleTypeName()
              + " attached = "
              + destination.getSimpleTypeName()
              + "."
              + getFindMethod().getMethodName().getSymbolName()
              + "(this."
              + identifierField.getFieldName().getSymbolName()
              + ");");
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".remove(attached);");
      bodyBuilder.indentRemove();
      bodyBuilder.appendFormalLine("}");
    } else {
      // Persist
      addTransactionalAnnotation(annotations, true);
      bodyBuilder.appendFormalLine(
          "this." + entityManagerFieldName + "." + methodDelegateName + "(this);");
    }

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            Modifier.PUBLIC,
            methodName,
            returnType,
            AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
            new ArrayList<JavaSymbolName>(),
            bodyBuilder);
    methodBuilder.setAnnotations(annotations);
    return methodBuilder.build();
  }
  public boolean updateTypeAnnotation(
      AnnotationMetadata annotation, Set<JavaSymbolName> attributesToDeleteIfPresent) {
    boolean hasChanged = false;

    // We are going to build a replacement AnnotationMetadata.
    // This variable tracks the new attribute values the replacement will hold.
    Map<JavaSymbolName, AnnotationAttributeValue<?>> replacementAttributeValues =
        new LinkedHashMap<JavaSymbolName, AnnotationAttributeValue<?>>();

    AnnotationMetadataBuilder existingBuilder =
        MemberFindingUtils.getDeclaredTypeAnnotation(this, annotation.getAnnotationType());

    if (existingBuilder == null) {
      // Not already present, so just go and add it
      for (JavaSymbolName incomingAttributeName : annotation.getAttributeNames()) {
        // Do not copy incoming attributes which exist in the attributesToDeleteIfPresent Set
        if (attributesToDeleteIfPresent == null
            || !attributesToDeleteIfPresent.contains(incomingAttributeName)) {
          AnnotationAttributeValue<?> incomingValue =
              annotation.getAttribute(incomingAttributeName);
          replacementAttributeValues.put(incomingAttributeName, incomingValue);
        }
      }

      AnnotationMetadataBuilder replacement =
          new AnnotationMetadataBuilder(
              annotation.getAnnotationType(),
              new ArrayList<AnnotationAttributeValue<?>>(replacementAttributeValues.values()));
      addAnnotation(replacement);
      return true;
    }

    AnnotationMetadata existing = existingBuilder.build();

    // Copy the existing attributes into the new attributes
    for (JavaSymbolName existingAttributeName : existing.getAttributeNames()) {
      if (attributesToDeleteIfPresent != null
          && attributesToDeleteIfPresent.contains(existingAttributeName)) {
        hasChanged = true;
      } else {
        AnnotationAttributeValue<?> existingValue = existing.getAttribute(existingAttributeName);
        replacementAttributeValues.put(existingAttributeName, existingValue);
      }
    }

    // Now we ensure every incoming attribute replaces the existing
    for (JavaSymbolName incomingAttributeName : annotation.getAttributeNames()) {
      AnnotationAttributeValue<?> incomingValue = annotation.getAttribute(incomingAttributeName);

      // Add this attribute to the end of the list if the attribute is not already present
      if (replacementAttributeValues.keySet().contains(incomingAttributeName)) {
        // There was already an attribute. Need to determine if this new attribute value is
        // materially different
        AnnotationAttributeValue<?> existingValue =
            replacementAttributeValues.get(incomingAttributeName);
        Assert.notNull(existingValue, "Existing value should have been provided by earlier loop");
        if (!existingValue.equals(incomingValue)) {
          replacementAttributeValues.put(incomingAttributeName, incomingValue);
          hasChanged = true;
        }
      } else if (attributesToDeleteIfPresent == null
          || !attributesToDeleteIfPresent.contains(incomingAttributeName)) {
        // This is a new attribute that does not already exist, so add it to the end of the
        // replacement attributes
        replacementAttributeValues.put(incomingAttributeName, incomingValue);
        hasChanged = true;
      }
    }
    // Were there any material changes?
    if (!hasChanged) {
      return false;
    }

    // Make a new AnnotationMetadata representing the replacement
    AnnotationMetadataBuilder replacement =
        new AnnotationMetadataBuilder(
            annotation.getAnnotationType(),
            new ArrayList<AnnotationAttributeValue<?>>(replacementAttributeValues.values()));
    annotations.remove(existingBuilder);
    addAnnotation(replacement);

    return true;
  }
  public IntegrationTestMetadata(
      final String identifier,
      final JavaType aspectName,
      final PhysicalTypeMetadata governorPhysicalTypeMetadata,
      final IntegrationTestAnnotationValues annotationValues,
      final DataOnDemandMetadata dataOnDemandMetadata,
      final MethodMetadata identifierAccessorMethod,
      final MethodMetadata versionAccessorMethod,
      final MemberTypeAdditions countMethod,
      final MemberTypeAdditions findMethod,
      final MemberTypeAdditions findAllMethod,
      final MemberTypeAdditions findEntriesMethod,
      final MemberTypeAdditions flushMethod,
      final MemberTypeAdditions mergeMethod,
      final MemberTypeAdditions persistMethod,
      final MemberTypeAdditions removeMethod,
      final String transactionManager,
      final boolean hasEmbeddedIdentifier,
      final boolean entityHasSuperclass,
      final boolean isGaeEnabled) {
    super(identifier, aspectName, governorPhysicalTypeMetadata);
    Assert.isTrue(
        isValid(identifier),
        "Metadata identification string '" + identifier + "' does not appear to be a valid");
    Assert.notNull(annotationValues, "Annotation values required");
    Assert.notNull(dataOnDemandMetadata, "Data on demand metadata required");

    if (!isValid()) {
      return;
    }

    this.annotationValues = annotationValues;
    this.dataOnDemandMetadata = dataOnDemandMetadata;
    this.transactionManager = transactionManager;
    this.hasEmbeddedIdentifier = hasEmbeddedIdentifier;
    this.entityHasSuperclass = entityHasSuperclass;

    addRequiredIntegrationTestClassIntroductions(
        DataOnDemandMetadata.getJavaType(dataOnDemandMetadata.getId()));

    // Add GAE LocalServiceTestHelper instance and @BeforeClass/@AfterClass
    // methods if GAE is enabled
    if (isGaeEnabled) {
      isGaeSupported = true;
      addOptionalIntegrationTestClassIntroductions();
    }

    builder.addMethod(getCountMethodTest(countMethod));
    builder.addMethod(getFindMethodTest(findMethod, identifierAccessorMethod));
    builder.addMethod(getFindAllMethodTest(findAllMethod, countMethod));
    builder.addMethod(getFindEntriesMethodTest(countMethod, findEntriesMethod));
    if (flushMethod != null) {
      builder.addMethod(
          getFlushMethodTest(
              versionAccessorMethod, identifierAccessorMethod, flushMethod, findMethod));
    }
    builder.addMethod(
        getMergeMethodTest(
            mergeMethod, findMethod, flushMethod, versionAccessorMethod, identifierAccessorMethod));
    builder.addMethod(getPersistMethodTest(persistMethod, flushMethod, identifierAccessorMethod));
    builder.addMethod(
        getRemoveMethodTest(removeMethod, findMethod, flushMethod, identifierAccessorMethod));

    itdTypeDetails = builder.build();
  }
  private void addOptionalIntegrationTestClassIntroductions() {
    // Add the GAE test helper field if the user did not define it on the
    // governor directly
    final JavaType helperType = GAE_LOCAL_SERVICE_TEST_HELPER;
    FieldMetadata helperField = governorTypeDetails.getField(new JavaSymbolName("helper"));
    if (helperField != null) {
      Assert.isTrue(
          helperField
              .getFieldType()
              .getFullyQualifiedTypeName()
              .equals(helperType.getFullyQualifiedTypeName()),
          "Field 'helper' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be of type '"
              + helperType.getFullyQualifiedTypeName()
              + "'");
    } else {
      // Add the field via the ITD
      String initializer =
          "new LocalServiceTestHelper(new com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig())";
      FieldMetadataBuilder fieldBuilder =
          new FieldMetadataBuilder(
              getId(),
              Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
              new JavaSymbolName("helper"),
              helperType,
              initializer);
      builder.addField(fieldBuilder);
    }

    // Prepare setUp method signature
    JavaSymbolName setUpMethodName = new JavaSymbolName("setUp");
    MethodMetadata setUpMethod = getGovernorMethod(setUpMethodName, SETUP_PARAMETERS);
    if (setUpMethod != null) {
      Assert.notNull(
          MemberFindingUtils.getAnnotationOfType(setUpMethod.getAnnotations(), BEFORE_CLASS),
          "Method 'setUp' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be annotated with @BeforeClass");
    } else {
      // Add the method via the ITD
      List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
      annotations.add(new AnnotationMetadataBuilder(BEFORE_CLASS));

      InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
      bodyBuilder.appendFormalLine("helper.setUp();");

      MethodMetadataBuilder methodBuilder =
          new MethodMetadataBuilder(
              getId(),
              Modifier.PUBLIC | Modifier.STATIC,
              setUpMethodName,
              JavaType.VOID_PRIMITIVE,
              AnnotatedJavaType.convertFromJavaTypes(SETUP_PARAMETERS),
              new ArrayList<JavaSymbolName>(),
              bodyBuilder);
      methodBuilder.setAnnotations(annotations);
      builder.addMethod(methodBuilder);
    }

    // Prepare tearDown method signature
    JavaSymbolName tearDownMethodName = new JavaSymbolName("tearDown");
    MethodMetadata tearDownMethod = getGovernorMethod(tearDownMethodName, TEARDOWN_PARAMETERS);
    if (tearDownMethod != null) {
      Assert.notNull(
          MemberFindingUtils.getAnnotationOfType(tearDownMethod.getAnnotations(), AFTER_CLASS),
          "Method 'tearDown' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be annotated with @AfterClass");
    } else {
      // Add the method via the ITD
      List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
      annotations.add(new AnnotationMetadataBuilder(AFTER_CLASS));

      InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
      bodyBuilder.appendFormalLine("helper.tearDown();");

      MethodMetadataBuilder methodBuilder =
          new MethodMetadataBuilder(
              getId(),
              Modifier.PUBLIC | Modifier.STATIC,
              tearDownMethodName,
              JavaType.VOID_PRIMITIVE,
              AnnotatedJavaType.convertFromJavaTypes(TEARDOWN_PARAMETERS),
              new ArrayList<JavaSymbolName>(),
              bodyBuilder);
      methodBuilder.setAnnotations(annotations);
      builder.addMethod(methodBuilder);
    }
  }
 public void focus(final GAV module) {
   Assert.notNull(module, "Specify the module to focus on");
   throw new UnsupportedOperationException(
       "Module focussing not implemented yet"); // TODO by JTT for ROO-120
 }
 public LogicalPath getFocusedPath(final Path path) {
   final PhysicalPath physicalPath = pomManagementService.getFocusedModule().getPhysicalPath(path);
   Assert.notNull(physicalPath, "Physical path for '" + path.name() + "' not found");
   return physicalPath.getLogicalPath();
 }
  /** Adds the JUnit and Spring type level annotations if needed */
  private void addRequiredIntegrationTestClassIntroductions(final JavaType dodGovernor) {
    // Add an @RunWith(SpringJunit4ClassRunner) annotation to the type, if
    // the user did not define it on the governor directly
    if (MemberFindingUtils.getAnnotationOfType(governorTypeDetails.getAnnotations(), RUN_WITH)
        == null) {
      AnnotationMetadataBuilder runWithBuilder = new AnnotationMetadataBuilder(RUN_WITH);
      runWithBuilder.addClassAttribute(
          "value", "org.springframework.test.context.junit4.SpringJUnit4ClassRunner");
      builder.addAnnotation(runWithBuilder);
    }

    // Add an @ContextConfiguration("classpath:/applicationContext.xml")
    // annotation to the type, if the user did not define it on the governor
    // directly
    if (MemberFindingUtils.getAnnotationOfType(
            governorTypeDetails.getAnnotations(), CONTEXT_CONFIGURATION)
        == null) {
      AnnotationMetadataBuilder contextConfigurationBuilder =
          new AnnotationMetadataBuilder(CONTEXT_CONFIGURATION);
      contextConfigurationBuilder.addStringAttribute(
          "locations", "classpath:/META-INF/spring/applicationContext*.xml");
      builder.addAnnotation(contextConfigurationBuilder);
    }

    // Add an @Transactional, if the user did not define it on the governor
    // directly
    if (annotationValues.isTransactional()
        && MemberFindingUtils.getAnnotationOfType(
                governorTypeDetails.getAnnotations(), TRANSACTIONAL)
            == null) {
      AnnotationMetadataBuilder transactionalBuilder = new AnnotationMetadataBuilder(TRANSACTIONAL);
      if (StringUtils.hasText(transactionManager)
          && !"transactionManager".equals(transactionManager)) {
        transactionalBuilder.addStringAttribute("value", transactionManager);
      }
      builder.addAnnotation(transactionalBuilder);
    }

    // Add the data on demand field if the user did not define it on the
    // governor directly
    FieldMetadata field = governorTypeDetails.getField(new JavaSymbolName("dod"));
    if (field != null) {
      Assert.isTrue(
          field.getFieldType().equals(dodGovernor),
          "Field 'dod' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be of type '"
              + dodGovernor.getFullyQualifiedTypeName()
              + "'");
      Assert.notNull(
          MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), AUTOWIRED),
          "Field 'dod' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be annotated with @Autowired");
    } else {
      // Add the field via the ITD
      List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
      annotations.add(new AnnotationMetadataBuilder(AUTOWIRED));
      FieldMetadataBuilder fieldBuilder =
          new FieldMetadataBuilder(
              getId(), Modifier.PRIVATE, annotations, new JavaSymbolName("dod"), dodGovernor);
      builder.addField(fieldBuilder);
    }

    builder.getImportRegistrationResolver().addImport(ASSERT);
  }
  private TemplateDataDictionary buildMirrorDataDictionary(
      final GwtType type,
      final ClassOrInterfaceTypeDetails mirroredType,
      final ClassOrInterfaceTypeDetails proxy,
      final Map<GwtType, JavaType> mirrorTypeMap,
      final Map<JavaSymbolName, GwtProxyProperty> clientSideTypeMap,
      final String moduleName) {
    JavaType proxyType = proxy.getName();
    JavaType javaType = mirrorTypeMap.get(type);

    TemplateDataDictionary dataDictionary = TemplateDictionary.create();

    // Get my locator and
    JavaType entity = mirroredType.getName();
    final String entityName = entity.getFullyQualifiedTypeName();
    String metadataIdentificationString = mirroredType.getDeclaredByMetadataId();
    final JavaType idType = persistenceMemberLocator.getIdentifierType(entity);
    Assert.notNull(idType, "Identifier type is not available for entity '" + entityName + "'");

    final MethodParameter entityParameter = new MethodParameter(entity, "proxy");
    ClassOrInterfaceTypeDetails request = gwtTypeService.lookupRequestFromProxy(proxy);

    MemberTypeAdditions persistMethodAdditions =
        layerService.getMemberTypeAdditions(
            metadataIdentificationString,
            CustomDataKeys.PERSIST_METHOD.name(),
            entity,
            idType,
            LAYER_POSITION,
            entityParameter);
    Assert.notNull(
        persistMethodAdditions, "Persist method is not available for entity '" + entityName + "'");
    String persistMethodSignature = getRequestMethodCall(request, persistMethodAdditions);
    dataDictionary.setVariable("persistMethodSignature", persistMethodSignature);

    MemberTypeAdditions removeMethodAdditions =
        layerService.getMemberTypeAdditions(
            metadataIdentificationString,
            CustomDataKeys.REMOVE_METHOD.name(),
            entity,
            idType,
            LAYER_POSITION,
            entityParameter);
    Assert.notNull(
        removeMethodAdditions, "Remove method is not available for entity '" + entityName + "'");
    String removeMethodSignature = getRequestMethodCall(request, removeMethodAdditions);
    dataDictionary.setVariable("removeMethodSignature", removeMethodSignature);

    MemberTypeAdditions countMethodAdditions =
        layerService.getMemberTypeAdditions(
            metadataIdentificationString,
            CustomDataKeys.COUNT_ALL_METHOD.name(),
            entity,
            idType,
            LAYER_POSITION);
    Assert.notNull(
        countMethodAdditions, "Count method is not available for entity '" + entityName + "'");
    dataDictionary.setVariable("countEntitiesMethod", countMethodAdditions.getMethodName());

    for (GwtType reference : type.getReferences()) {
      addReference(dataDictionary, reference, mirrorTypeMap);
    }

    addImport(dataDictionary, proxyType.getFullyQualifiedTypeName());

    String pluralMetadataKey =
        PluralMetadata.createIdentifier(
            mirroredType.getName(),
            PhysicalTypeIdentifier.getPath(mirroredType.getDeclaredByMetadataId()));
    PluralMetadata pluralMetadata = (PluralMetadata) metadataService.get(pluralMetadataKey);
    String plural = pluralMetadata.getPlural();

    final String simpleTypeName = mirroredType.getName().getSimpleTypeName();
    final JavaPackage topLevelPackage = projectOperations.getTopLevelPackage(moduleName);
    dataDictionary.setVariable("className", javaType.getSimpleTypeName());
    dataDictionary.setVariable("packageName", javaType.getPackage().getFullyQualifiedPackageName());
    dataDictionary.setVariable("placePackage", GwtPath.SCAFFOLD_PLACE.packageName(topLevelPackage));
    dataDictionary.setVariable(
        "scaffoldUiPackage", GwtPath.SCAFFOLD_UI.packageName(topLevelPackage));
    dataDictionary.setVariable(
        "sharedScaffoldPackage", GwtPath.SHARED_SCAFFOLD.packageName(topLevelPackage));
    dataDictionary.setVariable("uiPackage", GwtPath.MANAGED_UI.packageName(topLevelPackage));
    dataDictionary.setVariable("name", simpleTypeName);
    dataDictionary.setVariable("pluralName", plural);
    dataDictionary.setVariable("nameUncapitalized", StringUtils.uncapitalize(simpleTypeName));
    dataDictionary.setVariable("proxy", proxyType.getSimpleTypeName());
    dataDictionary.setVariable("pluralName", plural);
    dataDictionary.setVariable(
        "proxyRenderer", GwtProxyProperty.getProxyRendererType(topLevelPackage, proxyType));

    String proxyFields = null;
    GwtProxyProperty primaryProperty = null;
    GwtProxyProperty secondaryProperty = null;
    GwtProxyProperty dateProperty = null;
    Set<String> importSet = new HashSet<String>();

    for (GwtProxyProperty gwtProxyProperty : clientSideTypeMap.values()) {
      // Determine if this is the primary property.
      if (primaryProperty == null) {
        // Choose the first available field.
        primaryProperty = gwtProxyProperty;
      } else if (gwtProxyProperty.isString() && !primaryProperty.isString()) {
        // Favor String properties over other types.
        secondaryProperty = primaryProperty;
        primaryProperty = gwtProxyProperty;
      } else if (secondaryProperty == null) {
        // Choose the next available property.
        secondaryProperty = gwtProxyProperty;
      } else if (gwtProxyProperty.isString() && !secondaryProperty.isString()) {
        // Favor String properties over other types.
        secondaryProperty = gwtProxyProperty;
      }

      // Determine if this is the first date property.
      if (dateProperty == null && gwtProxyProperty.isDate()) {
        dateProperty = gwtProxyProperty;
      }

      if (gwtProxyProperty.isProxy() || gwtProxyProperty.isCollectionOfProxy()) {
        if (proxyFields != null) {
          proxyFields += ", ";
        } else {
          proxyFields = "";
        }
        proxyFields += "\"" + gwtProxyProperty.getName() + "\"";
      }

      dataDictionary.addSection("fields").setVariable("field", gwtProxyProperty.getName());
      if (!isReadOnly(gwtProxyProperty.getName(), mirroredType)) {
        dataDictionary
            .addSection("editViewProps")
            .setVariable("prop", gwtProxyProperty.forEditView());
      }

      TemplateDataDictionary propertiesSection = dataDictionary.addSection("properties");
      propertiesSection.setVariable("prop", gwtProxyProperty.getName());
      propertiesSection.setVariable(
          "propId", proxyType.getSimpleTypeName() + "_" + gwtProxyProperty.getName());
      propertiesSection.setVariable("propGetter", gwtProxyProperty.getGetter());
      propertiesSection.setVariable("propType", gwtProxyProperty.getType());
      propertiesSection.setVariable("propFormatter", gwtProxyProperty.getFormatter());
      propertiesSection.setVariable("propRenderer", gwtProxyProperty.getRenderer());
      propertiesSection.setVariable("propReadable", gwtProxyProperty.getReadableName());

      if (!isReadOnly(gwtProxyProperty.getName(), mirroredType)) {
        TemplateDataDictionary editableSection = dataDictionary.addSection("editableProperties");
        editableSection.setVariable("prop", gwtProxyProperty.getName());
        editableSection.setVariable(
            "propId", proxyType.getSimpleTypeName() + "_" + gwtProxyProperty.getName());
        editableSection.setVariable("propGetter", gwtProxyProperty.getGetter());
        editableSection.setVariable("propType", gwtProxyProperty.getType());
        editableSection.setVariable("propFormatter", gwtProxyProperty.getFormatter());
        editableSection.setVariable("propRenderer", gwtProxyProperty.getRenderer());
        editableSection.setVariable("propBinder", gwtProxyProperty.getBinder());
        editableSection.setVariable("propReadable", gwtProxyProperty.getReadableName());
      }

      dataDictionary.setVariable("proxyRendererType", proxyType.getSimpleTypeName() + "Renderer");

      if (gwtProxyProperty.isProxy()
          || gwtProxyProperty.isEnum()
          || gwtProxyProperty.isCollectionOfProxy()) {
        TemplateDataDictionary section =
            dataDictionary.addSection(
                gwtProxyProperty.isEnum() ? "setEnumValuePickers" : "setProxyValuePickers");
        section.setVariable("setValuePicker", gwtProxyProperty.getSetValuePickerMethod());
        section.setVariable("setValuePickerName", gwtProxyProperty.getSetValuePickerMethodName());
        section.setVariable("valueType", gwtProxyProperty.getValueType().getSimpleTypeName());
        section.setVariable("rendererType", gwtProxyProperty.getProxyRendererType());
        if (gwtProxyProperty.isProxy() || gwtProxyProperty.isCollectionOfProxy()) {
          String propTypeName =
              StringUtils.uncapitalize(
                  gwtProxyProperty.isCollectionOfProxy()
                      ? gwtProxyProperty
                          .getPropertyType()
                          .getParameters()
                          .get(0)
                          .getSimpleTypeName()
                      : gwtProxyProperty.getPropertyType().getSimpleTypeName());
          propTypeName = propTypeName.substring(0, propTypeName.indexOf("Proxy"));
          section.setVariable("requestInterface", propTypeName + "Request");
          section.setVariable(
              "findMethod", "find" + StringUtils.capitalize(propTypeName) + "Entries(0, 50)");
        }
        maybeAddImport(dataDictionary, importSet, gwtProxyProperty.getPropertyType());
        maybeAddImport(dataDictionary, importSet, gwtProxyProperty.getValueType());
        if (gwtProxyProperty.isCollectionOfProxy()) {
          maybeAddImport(
              dataDictionary, importSet, gwtProxyProperty.getPropertyType().getParameters().get(0));
          maybeAddImport(dataDictionary, importSet, gwtProxyProperty.getSetEditorType());
        }
      }
    }

    dataDictionary.setVariable("proxyFields", proxyFields);

    // Add a section for the mobile properties.
    if (primaryProperty != null) {
      dataDictionary.setVariable("primaryProp", primaryProperty.getName());
      dataDictionary.setVariable("primaryPropGetter", primaryProperty.getGetter());
      dataDictionary.setVariable(
          "primaryPropBuilder", primaryProperty.forMobileListView("primaryRenderer"));
      TemplateDataDictionary section = dataDictionary.addSection("mobileProperties");
      section.setVariable("prop", primaryProperty.getName());
      section.setVariable("propGetter", primaryProperty.getGetter());
      section.setVariable("propType", primaryProperty.getType());
      section.setVariable("propRenderer", primaryProperty.getRenderer());
      section.setVariable("propRendererName", "primaryRenderer");
    } else {
      dataDictionary.setVariable("primaryProp", "id");
      dataDictionary.setVariable("primaryPropGetter", "getId");
      dataDictionary.setVariable("primaryPropBuilder", "");
    }
    if (secondaryProperty != null) {
      dataDictionary.setVariable(
          "secondaryPropBuilder", secondaryProperty.forMobileListView("secondaryRenderer"));
      TemplateDataDictionary section = dataDictionary.addSection("mobileProperties");
      section.setVariable("prop", secondaryProperty.getName());
      section.setVariable("propGetter", secondaryProperty.getGetter());
      section.setVariable("propType", secondaryProperty.getType());
      section.setVariable("propRenderer", secondaryProperty.getRenderer());
      section.setVariable("propRendererName", "secondaryRenderer");
    } else {
      dataDictionary.setVariable("secondaryPropBuilder", "");
    }
    if (dateProperty != null) {
      dataDictionary.setVariable("datePropBuilder", dateProperty.forMobileListView("dateRenderer"));
      TemplateDataDictionary section = dataDictionary.addSection("mobileProperties");
      section.setVariable("prop", dateProperty.getName());
      section.setVariable("propGetter", dateProperty.getGetter());
      section.setVariable("propType", dateProperty.getType());
      section.setVariable("propRenderer", dateProperty.getRenderer());
      section.setVariable("propRendererName", "dateRenderer");
    } else {
      dataDictionary.setVariable("datePropBuilder", "");
    }
    return dataDictionary;
  }