Java tutorial
/* * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.gvnix.flex.ui; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.antlr.stringtemplate.StringTemplate; import org.antlr.stringtemplate.StringTemplateGroup; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.gvnix.flex.FlexOperations; import org.gvnix.flex.FlexScaffoldMetadata; import org.gvnix.flex.as.classpath.ASMutablePhysicalTypeMetadataProvider; import org.gvnix.flex.as.classpath.ASPhysicalTypeIdentifier; import org.gvnix.flex.as.classpath.ASPhysicalTypeMetadata; import org.gvnix.flex.as.classpath.details.ASFieldMetadata; import org.gvnix.flex.as.classpath.details.ASMutableClassOrInterfaceTypeDetails; import org.gvnix.flex.as.model.ActionScriptMappingUtils; import org.gvnix.flex.as.model.ActionScriptType; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.details.BeanInfoUtils; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.MemberFindingUtils; import org.springframework.roo.classpath.details.MethodMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.scanner.MemberDetails; import org.springframework.roo.classpath.scanner.MemberDetailsScanner; import org.springframework.roo.metadata.MetadataDependencyRegistry; import org.springframework.roo.metadata.MetadataIdentificationUtils; import org.springframework.roo.metadata.MetadataItem; import org.springframework.roo.metadata.MetadataNotificationListener; import org.springframework.roo.metadata.MetadataProvider; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.process.manager.FileManager; import org.springframework.roo.process.manager.MutableFile; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.Path; import org.springframework.roo.project.PathResolver; import org.springframework.roo.project.ProjectMetadata; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.support.logging.HandlerUtils; import org.springframework.roo.support.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * {@link MetadataProvider} for the user interface scaffolding for a Flex * remoting destination. * * @author Jeremy Grelle */ @Component @Service public class FlexUIMetadataProvider implements MetadataProvider, MetadataNotificationListener { protected final static Logger LOGGER = HandlerUtils.getLogger(FlexUIMetadataProvider.class); // ------------ OSGi component attributes ---------------- private BundleContext context; private PathResolver pathResolver; private MetadataDependencyRegistry metadataDependencyRegistry; private FileManager fileManager; private MetadataService metadataService; private ASMutablePhysicalTypeMetadataProvider asPhysicalTypeProvider; private FlexOperations flexOperations; private MemberDetailsScanner memberDetailsScanner; private ProjectOperations projectOperations; private StringTemplateGroup templateGroup; protected void activate(ComponentContext cContext) { context = cContext.getBundleContext(); getMetadataDependencyRegistry().registerDependency(FlexScaffoldMetadata.getMetadataIdentiferType(), getProvidesType()); this.templateGroup = new StringTemplateGroup("flexUIMetadataTemplateGroup"); } protected void deactivate(ComponentContext context) { getMetadataDependencyRegistry().deregisterDependency(FlexScaffoldMetadata.getMetadataIdentiferType(), getProvidesType()); } // TODO - For now this is mainly being driven by the JavaType referenced by // FlexScaffoldMetadata...should see if we // can make // things happen in the right order to be able to consistently rely on the // ActionScriptType instead public MetadataItem get(String metadataId) { // pluralCache = new HashMap<JavaType, String>(); JavaType javaType = FlexUIMetadata.getJavaType(metadataId); LogicalPath path = FlexUIMetadata.getPath(metadataId); String flexScaffoldMetadataKey = FlexScaffoldMetadata.createIdentifier(javaType, path); FlexScaffoldMetadata flexScaffoldMetadata = (FlexScaffoldMetadata) getMetadataService() .get(flexScaffoldMetadataKey); ProjectMetadata projectMetadata = (ProjectMetadata) getMetadataService() .get(ProjectMetadata.getProjectIdentifier(getProjectOperations().getFocusedModuleName())); if (flexScaffoldMetadata == null || !flexScaffoldMetadata.isValid() || projectMetadata == null || !projectMetadata.isValid()) { return null; } String presentationPackage = getProjectOperations() .getTopLevelPackage(getProjectOperations().getFocusedModuleName()) + ".presentation"; String entityPresentationPackage = presentationPackage + "." + flexScaffoldMetadata.getEntityReference().toLowerCase(); // Install the root application MXML document if it doesn't already // exist String scaffoldAppFileId = getPathResolver().getIdentifier(LogicalPath.getInstance(Path.ROOT, ""), "src/main/flex/" + getProjectOperations().getProjectName(getProjectOperations().getFocusedModuleName()) + "_scaffold.mxml"); if (!getFileManager().exists(scaffoldAppFileId)) { getFlexOperations().createScaffoldApp(); } updateScaffoldIfNecessary(scaffoldAppFileId, flexScaffoldMetadata); String flexConfigFileId = getPathResolver().getIdentifier(LogicalPath.getInstance(Path.ROOT, ""), "src/main/flex/" + getProjectOperations().getProjectName(getProjectOperations().getFocusedModuleName()) + "_scaffold-config.xml"); if (!getFileManager().exists(flexConfigFileId)) { getFlexOperations().createFlexCompilerConfig(); } updateCompilerConfigIfNecessary(flexConfigFileId, entityPresentationPackage, flexScaffoldMetadata); // Install the entity event class if it doesn't already exist ActionScriptType entityEventType = new ActionScriptType( entityPresentationPackage + "." + flexScaffoldMetadata.getEntity().getSimpleTypeName() + "Event"); if (!StringUtils.isNotBlank(getAsPhysicalTypeProvider().findIdentifier(entityEventType))) { createEntityEventType(entityEventType, flexScaffoldMetadata); } // Create or update the list view String listViewRelativePath = (entityPresentationPackage + "." + flexScaffoldMetadata.getEntity().getSimpleTypeName() + "View").replace('.', File.separatorChar) + ".mxml"; String listViewPath = getPathResolver().getIdentifier(LogicalPath.getInstance(Path.ROOT, ""), "src/main/flex/" + listViewRelativePath); writeToDiskIfNecessary(listViewPath, buildListViewDocument(flexScaffoldMetadata, getElegibleListFields(projectMetadata, flexScaffoldMetadata))); // Create or update the form view String formRelativePath = (entityPresentationPackage + "." + flexScaffoldMetadata.getEntity().getSimpleTypeName() + "Form").replace('.', File.separatorChar) + ".mxml"; String formPath = getPathResolver().getIdentifier(LogicalPath.getInstance(Path.ROOT, ""), "src/main/flex/" + formRelativePath); writeToDiskIfNecessary(formPath, buildFormDocument(flexScaffoldMetadata, getElegibleFormFields(projectMetadata, flexScaffoldMetadata))); return new FlexUIMetadata(metadataId); } private void updateScaffoldIfNecessary(String scaffoldAppFileId, FlexScaffoldMetadata flexScaffoldMetadata) { MutableFile scaffoldMutableFile = null; Document scaffoldDoc; try { scaffoldMutableFile = getFileManager().updateFile(scaffoldAppFileId); scaffoldDoc = XmlUtils.getDocumentBuilder().parse(scaffoldMutableFile.getInputStream()); } catch (Exception e) { throw new IllegalStateException(e); } String entityName = flexScaffoldMetadata.getEntity().getSimpleTypeName(); if (XmlUtils.findFirstElement( "/Application/Declarations/ArrayList[@id='entities' and String='" + entityName + "']", scaffoldDoc.getDocumentElement()) != null) { return; } Element entitiesElement = XmlUtils.findFirstElement("/Application/Declarations/ArrayList[@id='entities']", scaffoldDoc.getDocumentElement()); Validate.notNull(entitiesElement, "Could not find the entities element in the main scaffold mxml."); Element entityElement = scaffoldDoc.createElement("fx:String"); entityElement.setTextContent(entityName); entitiesElement.appendChild(entityElement); // Build a string representation of the MXML and write it to disk ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); XmlUtils.writeXml(XmlUtils.createIndentingTransformer(), byteArrayOutputStream, scaffoldDoc); String mxmlContent = byteArrayOutputStream.toString(); InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = IOUtils.toInputStream(mxmlContent); outputStream = scaffoldMutableFile.getOutputStream(); IOUtils.copy(inputStream, outputStream); } catch (Exception e) { throw new IllegalStateException(e); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); } } private void updateCompilerConfigIfNecessary(String flexConfigFileId, String entityPresentationPackage, FlexScaffoldMetadata flexScaffoldMetadata) { MutableFile flexConfigMutableFile = null; Document flexConfigDoc; try { flexConfigMutableFile = getFileManager().updateFile(flexConfigFileId); flexConfigDoc = XmlUtils.getDocumentBuilder().parse(flexConfigMutableFile.getInputStream()); } catch (Exception e) { throw new IllegalStateException(e); } String viewName = entityPresentationPackage + "." + flexScaffoldMetadata.getEntity().getSimpleTypeName() + "View"; if (XmlUtils.findFirstElement("/flex-config/includes[symbol='" + viewName + "']", flexConfigDoc.getDocumentElement()) != null) { return; } Element includesElement = XmlUtils.findFirstElement("/flex-config/includes", flexConfigDoc.getDocumentElement()); Validate.notNull(includesElement, "Could not find the includes element in the flex compiler config."); Element entityElement = flexConfigDoc.createElement("symbol"); entityElement.setTextContent(viewName); includesElement.appendChild(entityElement); // Build a string representation of the MXML and write it to disk ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); XmlUtils.writeXml(XmlUtils.createIndentingTransformer(), byteArrayOutputStream, flexConfigDoc); String mxmlContent = byteArrayOutputStream.toString(); InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = IOUtils.toInputStream(mxmlContent); outputStream = flexConfigMutableFile.getOutputStream(); IOUtils.copy(inputStream, outputStream); } catch (Exception e) { throw new IllegalStateException(e); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); } } public String getProvidesType() { return FlexUIMetadata.getMetadataIdentifierType(); } public void notify(String upstreamDependency, String downstreamDependency) { if (MetadataIdentificationUtils.isIdentifyingClass(downstreamDependency)) { Validate.isTrue( MetadataIdentificationUtils.getMetadataClass(upstreamDependency) .equals(MetadataIdentificationUtils .getMetadataClass(FlexScaffoldMetadata.getMetadataIdentiferType())), "Expected class-level notifications only for web scaffold metadata (not '" + upstreamDependency + "')"); // A physical Java type has changed, and determine what the // corresponding local metadata identification // string would have been JavaType javaType = FlexScaffoldMetadata.getJavaType(upstreamDependency); LogicalPath path = FlexScaffoldMetadata.getPath(upstreamDependency); downstreamDependency = FlexUIMetadata.createIdentifier(javaType, path); // We only need to proceed if the downstream dependency relationship // is not already registered // (if it's already registered, the event will be delivered directly // later on) if (getMetadataDependencyRegistry().getDownstream(upstreamDependency).contains(downstreamDependency)) { return; } } // We should now have an instance-specific "downstream dependency" that // can be processed by this class Validate.isTrue( MetadataIdentificationUtils.getMetadataClass(downstreamDependency) .equals(MetadataIdentificationUtils.getMetadataClass(getProvidesType())), "Unexpected downstream notification for '" + downstreamDependency + "' to this provider (which uses '" + getProvidesType() + "'"); getMetadataService().evict(downstreamDependency); if (get(downstreamDependency) != null) { getMetadataDependencyRegistry().notifyDownstream(downstreamDependency); } } private void createEntityEventType(ActionScriptType entityEventType, FlexScaffoldMetadata flexScaffoldMetadata) { ActionScriptType entityType = ActionScriptMappingUtils.toActionScriptType(flexScaffoldMetadata.getEntity()); StringTemplate entityEventTemplate = this.templateGroup .getInstanceOf("org/gvnix/flex/roo/addon/ui/entity_event"); entityEventTemplate.setAttribute("entityEventType", entityEventType); entityEventTemplate.setAttribute("entityType", entityType); entityEventTemplate.setAttribute("flexScaffoldMetadata", flexScaffoldMetadata); String relativePath = entityEventType.getFullyQualifiedTypeName().replace('.', File.separatorChar) + ".as"; String fileIdentifier = getPathResolver().getIdentifier(LogicalPath.getInstance(Path.ROOT, ""), "src/main/flex/" + relativePath); getFileManager().createOrUpdateTextFileIfRequired(fileIdentifier, entityEventTemplate.toString(), true); } private Document buildListViewDocument(FlexScaffoldMetadata flexScaffoldMetadata, List<FieldMetadata> elegibleFields) { ActionScriptType entityType = ActionScriptMappingUtils.toActionScriptType(flexScaffoldMetadata.getEntity()); StringTemplate listViewTemplate = this.templateGroup .getInstanceOf("org/gvnix/flex/roo/addon/ui/entity_list_view"); listViewTemplate.setAttribute("entityType", entityType); listViewTemplate.setAttribute("flexScaffoldMetadata", flexScaffoldMetadata); listViewTemplate.setAttribute("fields", elegibleFields); try { ByteArrayInputStream stream = new ByteArrayInputStream(listViewTemplate.toString().getBytes("UTF-8")); return XmlUtils.getDocumentBuilder().parse(stream); } catch (Exception e) { throw new IllegalStateException("Failed to build list view document", e); } } private Document buildFormDocument(FlexScaffoldMetadata flexScaffoldMetadata, List<FieldMetadata> elegibleFields) { ActionScriptType entityType = ActionScriptMappingUtils.toActionScriptType(flexScaffoldMetadata.getEntity()); StringTemplate listViewTemplate = this.templateGroup .getInstanceOf("org/gvnix/flex/roo/addon/ui/entity_form"); listViewTemplate.setAttribute("entityType", entityType); listViewTemplate.setAttribute("flexScaffoldMetadata", flexScaffoldMetadata); listViewTemplate.setAttribute("fields", wrapFields(elegibleFields)); Set<RelatedTypeWrapper> relatedTypes = findRelatedTypes(flexScaffoldMetadata, elegibleFields); listViewTemplate.setAttribute("relatedTypes", relatedTypes); listViewTemplate.setAttribute("labelFields", calculateLabelFields(relatedTypes)); try { ByteArrayInputStream stream = new ByteArrayInputStream(listViewTemplate.toString().getBytes("UTF-8")); return XmlUtils.getDocumentBuilder().parse(stream); } catch (Exception e) { throw new IllegalStateException("Failed to build list view document", e); } } // TODO - Provide a clean way for the user to specify a specific label via // metadata private Map<String, String> calculateLabelFields(Set<RelatedTypeWrapper> relatedTypes) { Map<String, String> labelFields = new HashMap<String, String>(); for (RelatedTypeWrapper relatedType : relatedTypes) { String labelField = "id"; // Default in case we don't find a better // candidate String asPhysicalTypeMetadataKey = ASPhysicalTypeIdentifier.createIdentifier(relatedType.getType(), "src/main/flex"); ASMutableClassOrInterfaceTypeDetails details = getASClassDetails(asPhysicalTypeMetadataKey); if (details == null) { continue; } for (ASFieldMetadata asField : details.getDeclaredFields()) { if (asField.getFieldType().equals(ActionScriptType.STRING_TYPE)) { labelField = asField.getFieldName().getSymbolName(); break; } } for (FieldMetadata fieldOfType : relatedType.fieldsOfType) { labelFields.put(fieldOfType.getFieldName().getSymbolName(), labelField); } } return labelFields; } private ASMutableClassOrInterfaceTypeDetails getASClassDetails(String metadataId) { ASPhysicalTypeMetadata metadata = (ASPhysicalTypeMetadata) getMetadataService().get(metadataId); if (metadata == null) { return null; } Validate.isInstanceOf(ASMutableClassOrInterfaceTypeDetails.class, metadata.getPhysicalTypeDetails(), "ActionScript entity must be a class or interface."); return (ASMutableClassOrInterfaceTypeDetails) metadata.getPhysicalTypeDetails(); } // TODO - Should we actually obtain the FlexScaffoldMetadata for the other // type? Could wind up in an infinite loop // if not careful private Set<RelatedTypeWrapper> findRelatedTypes(FlexScaffoldMetadata flexScaffoldMetadata, List<FieldMetadata> elegibleFields) { Set<RelatedTypeWrapper> relatedTypes = new LinkedHashSet<RelatedTypeWrapper>(); MemberDetails memberDetails = getMemberDetails(flexScaffoldMetadata.getEntity()); for (MethodMetadata method : MemberFindingUtils.getMethods(memberDetails)) { if (BeanInfoUtils.isAccessorMethod(method)) { JavaSymbolName propertyName = BeanInfoUtils.getPropertyNameForJavaBeanMethod(method); FieldMetadata javaField = BeanInfoUtils.getFieldForPropertyName(memberDetails, propertyName); if (null != MemberFindingUtils.getAnnotationOfType(javaField.getAnnotations(), new JavaType("javax.persistence.OneToOne")) || null != MemberFindingUtils.getAnnotationOfType(javaField.getAnnotations(), new JavaType("javax.persistence.ManyToOne"))) { ActionScriptType asType = ActionScriptMappingUtils.toActionScriptType(javaField.getFieldType()); relatedTypes .add(new RelatedTypeWrapper(asType, elegibleFields, !asType.getFullyQualifiedTypeName() .equals(flexScaffoldMetadata.getEntity().getFullyQualifiedTypeName()))); } } } return relatedTypes; } protected static List<FormFieldWrapper> wrapFields(List<FieldMetadata> elegibleFields) { List<FormFieldWrapper> wrappedFields = new ArrayList<FormFieldWrapper>(); for (FieldMetadata field : elegibleFields) { wrappedFields.add(new FormFieldWrapper(field)); } return wrappedFields; } private List<FieldMetadata> getElegibleListFields(ProjectMetadata projectMetadata, FlexScaffoldMetadata flexScaffoldMetadata) { List<FieldMetadata> eligibleFields = new ArrayList<FieldMetadata>(); MemberDetails memberDetails = getMemberDetails(flexScaffoldMetadata.getEntity()); for (MethodMetadata method : MemberFindingUtils.getMethods(memberDetails)) { if (BeanInfoUtils.isAccessorMethod(method)) { JavaSymbolName propertyName = BeanInfoUtils.getPropertyNameForJavaBeanMethod(method); FieldMetadata javaField = BeanInfoUtils.getFieldForPropertyName(memberDetails, propertyName); // TODO - For now we ignore relationships in the list view if (!javaField.getFieldType().isCommonCollectionType() && !javaField.getFieldType().isArray() && !javaField.getFieldType().getPackage().getFullyQualifiedPackageName() .startsWith(getProjectOperations() .getTopLevelPackage(getProjectOperations().getFocusedModuleName()) .getFullyQualifiedPackageName())) { // Never include id field if (MemberFindingUtils.getAnnotationOfType(javaField.getAnnotations(), new JavaType("javax.persistence.Id")) != null) { continue; } // Never include version field if (MemberFindingUtils.getAnnotationOfType(javaField.getAnnotations(), new JavaType("javax.persistence.Version")) != null) { continue; } eligibleFields.add(javaField); } } } return eligibleFields; } private List<FieldMetadata> getElegibleFormFields(ProjectMetadata projectMetadata, FlexScaffoldMetadata flexScaffoldMetadata) { List<FieldMetadata> eligibleFields = new ArrayList<FieldMetadata>(); MemberDetails memberDetails = getMemberDetails(flexScaffoldMetadata.getEntity()); for (MethodMetadata method : MemberFindingUtils.getMethods(memberDetails)) { if (BeanInfoUtils.isAccessorMethod(method)) { JavaSymbolName propertyName = BeanInfoUtils.getPropertyNameForJavaBeanMethod(method); FieldMetadata javaField = BeanInfoUtils.getFieldForPropertyName(memberDetails, propertyName); // TODO - For now we ignore relationships in the list view if (!javaField.getFieldType().isCommonCollectionType() && !javaField.getFieldType().isArray()) { // Never include id field if (MemberFindingUtils.getAnnotationOfType(javaField.getAnnotations(), new JavaType("javax.persistence.Id")) != null) { continue; } // Never include version field if (MemberFindingUtils.getAnnotationOfType(javaField.getAnnotations(), new JavaType("javax.persistence.Version")) != null) { continue; } eligibleFields.add(javaField); } } } return eligibleFields; } /** return indicates if disk was changed (ie updated or created) */ private boolean writeToDiskIfNecessary(String mxmlFilename, Document proposed) { Document original = null; // If mutableFile becomes non-null, it means we need to use it to write // out the contents of jspContent to the // file MutableFile mutableFile = null; if (getFileManager().exists(mxmlFilename)) { InputStream inStream = null; try { inStream = getFileManager().getInputStream(mxmlFilename); original = XmlUtils.getDocumentBuilder().parse(inStream); } catch (Exception e) { throw new IllegalStateException("Could not parse file: ".concat(mxmlFilename)); } finally { IOUtils.closeQuietly(inStream); } Validate.notNull(original, "Unable to parse ".concat(mxmlFilename)); if (MxmlRoundTripUtils.compareDocuments(original, proposed)) { // TODO // - // need // to // actually // implement // the // comparison // algorithm // in // a // way // that // works // for // MXML // to // allow // non-destructive // editing mutableFile = getFileManager().updateFile(mxmlFilename); } } else { original = proposed; mutableFile = getFileManager().createFile(mxmlFilename); Validate.notNull(mutableFile, "Could not create MXML file '".concat(mxmlFilename).concat("'")); } try { if (mutableFile != null) { // Build a string representation of the MXML ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); XmlUtils.writeXml(XmlUtils.createIndentingTransformer(), byteArrayOutputStream, original); String mxmlContent = byteArrayOutputStream.toString(); // We need to write the file out (it's a new file, or the // existing file has different contents) InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = IOUtils.toInputStream(mxmlContent); outputStream = mutableFile.getOutputStream(); IOUtils.copy(inputStream, outputStream); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); } // Return and indicate we wrote out the file return true; } } catch (IOException ioe) { throw new IllegalStateException("Could not output '".concat(mutableFile.getCanonicalPath()).concat("'"), ioe); } // A file existed, but it contained the same content, so we return false return false; } private MemberDetails getMemberDetails(JavaType entityType) { PhysicalTypeMetadata entityPhysicalTypeMetadata = (PhysicalTypeMetadata) getMetadataService() .get(PhysicalTypeIdentifier.createIdentifier(entityType, LogicalPath.getInstance(Path.SRC_MAIN_JAVA, ""))); Validate.notNull(entityPhysicalTypeMetadata, "Unable to obtain physical type metdata for type ".concat(entityType.getFullyQualifiedTypeName())); ClassOrInterfaceTypeDetails entityClassOrInterfaceDetails = (ClassOrInterfaceTypeDetails) entityPhysicalTypeMetadata .getMemberHoldingTypeDetails(); return scanForMemberDetails(entityClassOrInterfaceDetails); } private MemberDetails scanForMemberDetails(ClassOrInterfaceTypeDetails entityClassOrInterfaceDetails) { return getMemberDetailsScanner().getMemberDetails(getClass().getName(), entityClassOrInterfaceDetails); } protected static Map<String, String> buildValidationsForField(FieldMetadata field) { Map<String, String> validations = new HashMap<String, String>(); AnnotationMetadata annotationMetadata; if (null != (annotationMetadata = MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), new JavaType("javax.validation.constraints.Min")))) { AnnotationAttributeValue<?> min = annotationMetadata.getAttribute(new JavaSymbolName("value")); if (min != null) { validations.put("minValue", min.getValue().toString()); } } if (null != (annotationMetadata = MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), new JavaType("javax.validation.constraints.Max")))) { AnnotationAttributeValue<?> max = annotationMetadata.getAttribute(new JavaSymbolName("value")); if (max != null) { validations.put("maxValue", max.getValue().toString()); } } if (null != (annotationMetadata = MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), new JavaType("javax.validation.constraints.Pattern")))) { AnnotationAttributeValue<?> regexp = annotationMetadata.getAttribute(new JavaSymbolName("regexp")); if (regexp != null) { validations.put("expression", regexp.getValue().toString()); } } if (null != (annotationMetadata = MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), new JavaType("javax.validation.constraints.Size")))) { AnnotationAttributeValue<?> max = annotationMetadata.getAttribute(new JavaSymbolName("max")); if (max != null) { validations.put("maxLength", max.getValue().toString()); } AnnotationAttributeValue<?> min = annotationMetadata.getAttribute(new JavaSymbolName("min")); if (min != null) { validations.put("minLength", min.getValue().toString()); } } if (null != (annotationMetadata = MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), new JavaType("javax.validation.constraints.NotNull")))) { validations.put("required", "true"); } return validations.size() > 0 ? validations : null; } public static final class FormFieldWrapper { private final FieldMetadata metadata; private final Map<String, String> validations; public FormFieldWrapper(FieldMetadata metadata) { this.metadata = metadata; this.validations = buildValidationsForField(metadata); } public FieldMetadata getMetadata() { return this.metadata; } public Map<String, String> getValidations() { return this.validations; } public Boolean isDate() { return ActionScriptMappingUtils.toActionScriptType(this.metadata.getFieldType()) .equals(ActionScriptType.DATE_TYPE); } public Boolean isBoolean() { return ActionScriptMappingUtils.toActionScriptType(this.metadata.getFieldType()) .equals(ActionScriptType.BOOLEAN_TYPE); } public Boolean isNumber() { return ActionScriptMappingUtils.toActionScriptType(this.metadata.getFieldType()).isNumeric(); } public Boolean isSingleEndedRelationship() { if (ActionScriptMappingUtils .isMappableType(ActionScriptMappingUtils.toActionScriptType(this.metadata.getFieldType()))) { return null != MemberFindingUtils.getAnnotationOfType(this.metadata.getAnnotations(), new JavaType("javax.persistence.OneToOne")) || null != MemberFindingUtils.getAnnotationOfType(this.metadata.getAnnotations(), new JavaType("javax.persistence.ManyToOne")); } return false; } } public static final class RelatedTypeWrapper { private final ActionScriptType asType; private final List<FieldMetadata> fieldsOfType = new ArrayList<FieldMetadata>(); private final boolean importRequired; public RelatedTypeWrapper(ActionScriptType asType, List<FieldMetadata> elegibleFields, boolean importRequired) { this.asType = asType; this.importRequired = importRequired; for (FieldMetadata field : elegibleFields) { if (field.getFieldType().getFullyQualifiedTypeName().equals(asType.getFullyQualifiedTypeName())) { this.fieldsOfType.add(field); } } } public String getServiceReference() { return StringUtils.uncapitalize(this.asType.getSimpleTypeName()) + "Service"; } public List<FieldMetadata> getFieldsOfType() { return this.fieldsOfType; } public ActionScriptType getType() { return this.asType; } public String getTypeName() { return this.asType.getSimpleTypeName(); } public String getTypeReference() { return StringUtils.uncapitalize(this.asType.getSimpleTypeName()); } public Boolean isImportRequired() { return this.importRequired; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.asType == null ? 0 : this.asType.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } RelatedTypeWrapper other = (RelatedTypeWrapper) obj; if (this.asType == null) { if (other.asType != null) { return false; } } else if (!this.asType.equals(other.asType)) { return false; } return true; } } public PathResolver getPathResolver() { if (pathResolver == null) { // Get all Services implement PathResolver interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(PathResolver.class.getName(), null); for (ServiceReference<?> ref : references) { return (PathResolver) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load PathResolver on FlexUIMetadataProvider."); return null; } } else { return pathResolver; } } public MetadataDependencyRegistry getMetadataDependencyRegistry() { if (metadataDependencyRegistry == null) { // Get all Services implement MetadataDependencyRegistry interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(MetadataDependencyRegistry.class.getName(), null); for (ServiceReference<?> ref : references) { return (MetadataDependencyRegistry) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load MetadataDependencyRegistry on FlexUIMetadataProvider."); return null; } } else { return metadataDependencyRegistry; } } public FileManager getFileManager() { if (fileManager == null) { // Get all Services implement FileManager interface try { ServiceReference<?>[] references = this.context.getAllServiceReferences(FileManager.class.getName(), null); for (ServiceReference<?> ref : references) { return (FileManager) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load FileManager on FlexUIMetadataProvider."); return null; } } else { return fileManager; } } public MetadataService getMetadataService() { if (metadataService == null) { // Get all Services implement MetadataService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(MetadataService.class.getName(), null); for (ServiceReference<?> ref : references) { return (MetadataService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load MetadataService on FlexUIMetadataProvider."); return null; } } else { return metadataService; } } public ASMutablePhysicalTypeMetadataProvider getAsPhysicalTypeProvider() { if (asPhysicalTypeProvider == null) { // Get all Services implement ASMutablePhysicalTypeMetadataProvider // interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(ASMutablePhysicalTypeMetadataProvider.class.getName(), null); for (ServiceReference<?> ref : references) { return (ASMutablePhysicalTypeMetadataProvider) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load ASMutablePhysicalTypeMetadataProvider on FlexUIMetadataProvider."); return null; } } else { return asPhysicalTypeProvider; } } public FlexOperations getFlexOperations() { if (flexOperations == null) { // Get all Services implement FlexOperations interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(FlexOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (FlexOperations) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load FlexOperations on FlexUIMetadataProvider."); return null; } } else { return flexOperations; } } public MemberDetailsScanner getMemberDetailsScanner() { if (memberDetailsScanner == null) { // Get all Services implement MemberDetailsScanner interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(MemberDetailsScanner.class.getName(), null); for (ServiceReference<?> ref : references) { return (MemberDetailsScanner) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load MemberDetailsScanner on FlexUIMetadataProvider."); return null; } } else { return memberDetailsScanner; } } public ProjectOperations getProjectOperations() { if (projectOperations == null) { // Get all Services implement ProjectOperations interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(ProjectOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (ProjectOperations) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load ProjectOperations on FlexUIMetadataProvider."); return null; } } else { return projectOperations; } } }