/** * Provides a basic implementation of {@link GwtTemplateService} which is used to create {@link * ClassOrInterfaceTypeDetails} objects from source files created from templates. This class keeps * all templating concerns in one place. * * @author James Tyrrell * @since 1.1.2 */ @Component @Service public class GwtTemplateServiceImpl implements GwtTemplateService { private static final int LAYER_POSITION = LayerType.HIGHEST.getPosition(); @Reference GwtTypeService gwtTypeService; @Reference LayerService layerService; @Reference MetadataService metadataService; @Reference PersistenceMemberLocator persistenceMemberLocator; @Reference ProjectOperations projectOperations; @Reference TypeLocationService typeLocationService; @Reference TypeParsingService typeParsingService; private void addImport(final TemplateDataDictionary dataDictionary, final JavaType type) { dataDictionary.addSection("imports").setVariable("import", type.getFullyQualifiedTypeName()); for (final JavaType param : type.getParameters()) { addImport(dataDictionary, param.getFullyQualifiedTypeName()); } } private void addImport( final TemplateDataDictionary dataDictionary, final String importDeclaration) { dataDictionary.addSection("imports").setVariable("import", importDeclaration); } private void addImport( final TemplateDataDictionary dataDictionary, final String simpleName, final GwtType gwtType, final String moduleName) { addImport( dataDictionary, gwtType.getPath().packageName(projectOperations.getTopLevelPackage(moduleName)) + "." + simpleName + gwtType.getSuffix()); } private void addReference( final TemplateDataDictionary dataDictionary, final GwtType type, final Map<GwtType, JavaType> mirrorTypeMap) { addImport(dataDictionary, mirrorTypeMap.get(type).getFullyQualifiedTypeName()); dataDictionary.setVariable(type.getName(), mirrorTypeMap.get(type).getSimpleTypeName()); } private void addReference( final TemplateDataDictionary dataDictionary, final GwtType type, final String moduleName) { addImport(dataDictionary, getDestinationJavaType(type, moduleName).getFullyQualifiedTypeName()); dataDictionary.setVariable( type.getName(), getDestinationJavaType(type, moduleName).getSimpleTypeName()); } private TemplateDataDictionary buildDictionary(final GwtType type, final String moduleName) { final Set<ClassOrInterfaceTypeDetails> proxies = typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(RooJavaType.ROO_GWT_PROXY); final TemplateDataDictionary dataDictionary = buildStandardDataDictionary(type, moduleName); switch (type) { case APP_ENTITY_TYPES_PROCESSOR: for (final ClassOrInterfaceTypeDetails proxy : proxies) { if (!GwtUtils.scaffoldProxy(proxy)) { continue; } final String proxySimpleName = proxy.getName().getSimpleTypeName(); final ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy); if (entity != null) { final String entitySimpleName = entity.getName().getSimpleTypeName(); dataDictionary.addSection("proxys").setVariable("proxy", proxySimpleName); final String entity1 = new StringBuilder("\t\tif (") .append(proxySimpleName) .append(".class.equals(clazz)) {\n\t\t\tprocessor.handle") .append(entitySimpleName) .append("((") .append(proxySimpleName) .append(") null);\n\t\t\treturn;\n\t\t}") .toString(); dataDictionary.addSection("entities1").setVariable("entity", entity1); final String entity2 = new StringBuilder("\t\tif (proxy instanceof ") .append(proxySimpleName) .append(") {\n\t\t\tprocessor.handle") .append(entitySimpleName) .append("((") .append(proxySimpleName) .append(") proxy);\n\t\t\treturn;\n\t\t}") .toString(); dataDictionary.addSection("entities2").setVariable("entity", entity2); final String entity3 = new StringBuilder("\tpublic abstract void handle") .append(entitySimpleName) .append("(") .append(proxySimpleName) .append(" proxy);") .toString(); dataDictionary.addSection("entities3").setVariable("entity", entity3); addImport(dataDictionary, proxy.getName().getFullyQualifiedTypeName()); } } break; case MASTER_ACTIVITIES: for (final ClassOrInterfaceTypeDetails proxy : proxies) { if (!GwtUtils.scaffoldProxy(proxy)) { continue; } final String proxySimpleName = proxy.getName().getSimpleTypeName(); final ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy); if (entity != null && !Modifier.isAbstract(entity.getModifier())) { final String entitySimpleName = entity.getName().getSimpleTypeName(); final TemplateDataDictionary section = dataDictionary.addSection("entities"); section.setVariable("entitySimpleName", entitySimpleName); section.setVariable("entityFullPath", proxySimpleName); addImport(dataDictionary, entitySimpleName, GwtType.LIST_ACTIVITY, moduleName); addImport(dataDictionary, proxy.getName().getFullyQualifiedTypeName()); addImport(dataDictionary, entitySimpleName, GwtType.LIST_VIEW, moduleName); addImport(dataDictionary, entitySimpleName, GwtType.MOBILE_LIST_VIEW, moduleName); } } break; case APP_REQUEST_FACTORY: for (final ClassOrInterfaceTypeDetails proxy : proxies) { if (!GwtUtils.scaffoldProxy(proxy)) { continue; } final ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy); if (entity != null && !Modifier.isAbstract(entity.getModifier())) { final String entitySimpleName = entity.getName().getSimpleTypeName(); final ClassOrInterfaceTypeDetails request = gwtTypeService.lookupRequestFromProxy(proxy); if (request != null) { final String requestExpression = new StringBuilder("\t") .append(request.getName().getSimpleTypeName()) .append(" ") .append(StringUtils.uncapitalize(entitySimpleName)) .append("Request();") .toString(); dataDictionary.addSection("entities").setVariable("entity", requestExpression); addImport(dataDictionary, request.getName().getFullyQualifiedTypeName()); } } dataDictionary.setVariable( "sharedScaffoldPackage", GwtPath.SHARED_SCAFFOLD.packageName( projectOperations.getTopLevelPackage(moduleName))); } if (projectOperations.isFeatureInstalledInFocusedModule(FeatureNames.GAE)) { dataDictionary.showSection("gae"); } break; case LIST_PLACE_RENDERER: for (final ClassOrInterfaceTypeDetails proxy : proxies) { if (!GwtUtils.scaffoldProxy(proxy)) { continue; } final ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy); if (entity != null) { final String entitySimpleName = entity.getName().getSimpleTypeName(); final String proxySimpleName = proxy.getName().getSimpleTypeName(); final TemplateDataDictionary section = dataDictionary.addSection("entities"); section.setVariable("entitySimpleName", entitySimpleName); section.setVariable("entityFullPath", proxySimpleName); addImport(dataDictionary, proxy.getName().getFullyQualifiedTypeName()); } } break; case DETAILS_ACTIVITIES: for (final ClassOrInterfaceTypeDetails proxy : proxies) { if (!GwtUtils.scaffoldProxy(proxy)) { continue; } final ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy); if (entity != null) { final String proxySimpleName = proxy.getName().getSimpleTypeName(); final String entitySimpleName = entity.getName().getSimpleTypeName(); final String entityExpression = new StringBuilder("\t\t\tpublic void handle") .append(entitySimpleName) .append("(") .append(proxySimpleName) .append(" proxy) {\n") .append("\t\t\t\tsetResult(new ") .append(entitySimpleName) .append( "ActivitiesMapper(requests, placeController).getActivity(proxyPlace));\n\t\t\t}") .toString(); dataDictionary.addSection("entities").setVariable("entity", entityExpression); addImport(dataDictionary, proxy.getName().getFullyQualifiedTypeName()); addImport( dataDictionary, GwtType.ACTIVITIES_MAPPER .getPath() .packageName(projectOperations.getTopLevelPackage(moduleName)) + "." + entitySimpleName + GwtType.ACTIVITIES_MAPPER.getSuffix()); } } break; case MOBILE_ACTIVITIES: // Do nothing break; } return dataDictionary; } 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) { final JavaType proxyType = proxy.getName(); final JavaType javaType = mirrorTypeMap.get(type); final TemplateDataDictionary dataDictionary = TemplateDictionary.create(); // Get my locator and final JavaType entity = mirroredType.getName(); final String entityName = entity.getFullyQualifiedTypeName(); final String metadataIdentificationString = mirroredType.getDeclaredByMetadataId(); final JavaType idType = persistenceMemberLocator.getIdentifierType(entity); Validate.notNull(idType, "Identifier type is not available for entity '" + entityName + "'"); final MethodParameter entityParameter = new MethodParameter(entity, "proxy"); final ClassOrInterfaceTypeDetails request = gwtTypeService.lookupRequestFromProxy(proxy); final MemberTypeAdditions persistMethodAdditions = layerService.getMemberTypeAdditions( metadataIdentificationString, CustomDataKeys.PERSIST_METHOD.name(), entity, idType, LAYER_POSITION, entityParameter); Validate.notNull( persistMethodAdditions, "Persist method is not available for entity '" + entityName + "'"); final String persistMethodSignature = getRequestMethodCall(request, persistMethodAdditions); dataDictionary.setVariable("persistMethodSignature", persistMethodSignature); final MemberTypeAdditions removeMethodAdditions = layerService.getMemberTypeAdditions( metadataIdentificationString, CustomDataKeys.REMOVE_METHOD.name(), entity, idType, LAYER_POSITION, entityParameter); Validate.notNull( removeMethodAdditions, "Remove method is not available for entity '" + entityName + "'"); final String removeMethodSignature = getRequestMethodCall(request, removeMethodAdditions); dataDictionary.setVariable("removeMethodSignature", removeMethodSignature); final MemberTypeAdditions countMethodAdditions = layerService.getMemberTypeAdditions( metadataIdentificationString, CustomDataKeys.COUNT_ALL_METHOD.name(), entity, idType, LAYER_POSITION); Validate.notNull( countMethodAdditions, "Count method is not available for entity '" + entityName + "'"); dataDictionary.setVariable("countEntitiesMethod", countMethodAdditions.getMethodName()); for (final GwtType reference : type.getReferences()) { addReference(dataDictionary, reference, mirrorTypeMap); } addImport(dataDictionary, proxyType.getFullyQualifiedTypeName()); final String pluralMetadataKey = PluralMetadata.createIdentifier( mirroredType.getName(), PhysicalTypeIdentifier.getPath(mirroredType.getDeclaredByMetadataId())); final PluralMetadata pluralMetadata = (PluralMetadata) metadataService.get(pluralMetadataKey); final 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; final Set<String> importSet = new HashSet<String>(); for (final 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()); } final 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)) { final 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()) { final 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")); final 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")); final 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")); final 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; } private TemplateDataDictionary buildStandardDataDictionary( final GwtType type, final String moduleName) { final JavaType javaType = new JavaType(getFullyQualifiedTypeName(type, moduleName)); final TemplateDataDictionary dataDictionary = TemplateDictionary.create(); for (final GwtType reference : type.getReferences()) { addReference(dataDictionary, reference, moduleName); } dataDictionary.setVariable("className", javaType.getSimpleTypeName()); dataDictionary.setVariable("packageName", javaType.getPackage().getFullyQualifiedPackageName()); dataDictionary.setVariable( "placePackage", GwtPath.SCAFFOLD_PLACE.packageName(projectOperations.getTopLevelPackage(moduleName))); dataDictionary.setVariable( "sharedScaffoldPackage", GwtPath.SHARED_SCAFFOLD.packageName(projectOperations.getTopLevelPackage(moduleName))); dataDictionary.setVariable( "sharedGaePackage", GwtPath.SHARED_GAE.packageName(projectOperations.getTopLevelPackage(moduleName))); return dataDictionary; } public String buildUiXml( final String templateContents, final String destFile, final List<MethodMetadata> proxyMethods) { FileReader fileReader = null; try { final DocumentBuilder builder = XmlUtils.getDocumentBuilder(); builder.setEntityResolver( new EntityResolver() { public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException { if (systemId.equals("http://dl.google.com/gwt/DTD/xhtml.ent")) { return new InputSource( FileUtils.getInputStream(GwtScaffoldMetadata.class, "templates/xhtml.ent")); } // Use the default behaviour return null; } }); InputSource source = new InputSource(); source.setCharacterStream(new StringReader(templateContents)); final Document templateDocument = builder.parse(source); if (!new File(destFile).exists()) { return transformXml(templateDocument); } source = new InputSource(); fileReader = new FileReader(destFile); source.setCharacterStream(fileReader); final Document existingDocument = builder.parse(source); // Look for the element holder denoted by the 'debugId' attribute // first Element existingHoldingElement = XmlUtils.findFirstElement( "//*[@debugId='" + "boundElementHolder" + "']", existingDocument.getDocumentElement()); Element templateHoldingElement = XmlUtils.findFirstElement( "//*[@debugId='" + "boundElementHolder" + "']", templateDocument.getDocumentElement()); // If holding element isn't found then the holding element is either // not widget based or using the old convention of 'id' so look for // the element holder with an 'id' attribute if (existingHoldingElement == null) { existingHoldingElement = XmlUtils.findFirstElement( "//*[@id='" + "boundElementHolder" + "']", existingDocument.getDocumentElement()); } if (templateHoldingElement == null) { templateHoldingElement = XmlUtils.findFirstElement( "//*[@id='" + "boundElementHolder" + "']", templateDocument.getDocumentElement()); } if (existingHoldingElement != null) { final Map<String, Element> templateElementMap = new LinkedHashMap<String, Element>(); for (final Element element : XmlUtils.findElements("//*[@id]", templateHoldingElement)) { templateElementMap.put(element.getAttribute("id"), element); } final Map<String, Element> existingElementMap = new LinkedHashMap<String, Element>(); for (final Element element : XmlUtils.findElements("//*[@id]", existingHoldingElement)) { existingElementMap.put(element.getAttribute("id"), element); } if (existingElementMap.keySet().containsAll(templateElementMap.values())) { return transformXml(existingDocument); } final List<Element> elementsToAdd = new ArrayList<Element>(); for (final Map.Entry<String, Element> entry : templateElementMap.entrySet()) { if (!existingElementMap.keySet().contains(entry.getKey())) { elementsToAdd.add(entry.getValue()); } } final List<Element> elementsToRemove = new ArrayList<Element>(); for (final Map.Entry<String, Element> entry : existingElementMap.entrySet()) { if (!templateElementMap.keySet().contains(entry.getKey())) { elementsToRemove.add(entry.getValue()); } } for (final Element element : elementsToAdd) { final Node importedNode = existingDocument.importNode(element, true); existingHoldingElement.appendChild(importedNode); } for (final Element element : elementsToRemove) { existingHoldingElement.removeChild(element); } if (elementsToAdd.size() > 0) { final List<Element> sortedElements = new ArrayList<Element>(); for (final MethodMetadata method : proxyMethods) { final String propertyName = StringUtils.uncapitalize( BeanInfoUtils.getPropertyNameForJavaBeanMethod(method).getSymbolName()); final Element element = XmlUtils.findFirstElement( "//*[@id='" + propertyName + "']", existingHoldingElement); if (element != null) { sortedElements.add(element); } } for (final Element el : sortedElements) { if (el.getParentNode() != null && el.getParentNode().equals(existingHoldingElement)) { existingHoldingElement.removeChild(el); } } for (final Element el : sortedElements) { existingHoldingElement.appendChild(el); } } return transformXml(existingDocument); } return transformXml(templateDocument); } catch (final Exception e) { throw new IllegalStateException(e); } finally { IOUtils.closeQuietly(fileReader); } } private JavaType getCollectionImplementation(final JavaType javaType) { if (isSameBaseType(javaType, SET)) { return new JavaType( HASH_SET.getFullyQualifiedTypeName(), javaType.getArray(), javaType.getDataType(), javaType.getArgName(), javaType.getParameters()); } if (isSameBaseType(javaType, LIST)) { return new JavaType( ARRAY_LIST.getFullyQualifiedTypeName(), javaType.getArray(), javaType.getDataType(), javaType.getArgName(), javaType.getParameters()); } return javaType; } private JavaType getDestinationJavaType(final GwtType destType, final String moduleName) { return new JavaType(getFullyQualifiedTypeName(destType, moduleName)); } private String getFullyQualifiedTypeName(final GwtType gwtType, final String moduleName) { return gwtType.getPath().packageName(projectOperations.getTopLevelPackage(moduleName)) + "." + gwtType.getTemplate(); } public GwtTemplateDataHolder getMirrorTemplateTypeDetails( final ClassOrInterfaceTypeDetails mirroredType, final Map<JavaSymbolName, GwtProxyProperty> clientSideTypeMap, final String moduleName) { final ClassOrInterfaceTypeDetails proxy = gwtTypeService.lookupProxyFromEntity(mirroredType); final ClassOrInterfaceTypeDetails request = gwtTypeService.lookupRequestFromEntity(mirroredType); final JavaPackage topLevelPackage = projectOperations.getTopLevelPackage(moduleName); final Map<GwtType, JavaType> mirrorTypeMap = GwtUtils.getMirrorTypeMap(mirroredType.getName(), topLevelPackage); mirrorTypeMap.put(GwtType.PROXY, proxy.getName()); mirrorTypeMap.put(GwtType.REQUEST, request.getName()); final Map<GwtType, ClassOrInterfaceTypeDetails> templateTypeDetailsMap = new LinkedHashMap<GwtType, ClassOrInterfaceTypeDetails>(); final Map<GwtType, String> xmlTemplates = new LinkedHashMap<GwtType, String>(); for (final GwtType gwtType : GwtType.getMirrorTypes()) { if (gwtType.getTemplate() == null) { continue; } TemplateDataDictionary dataDictionary = buildMirrorDataDictionary( gwtType, mirroredType, proxy, mirrorTypeMap, clientSideTypeMap, moduleName); gwtType.dynamicallyResolveFieldsToWatch(clientSideTypeMap); gwtType.dynamicallyResolveMethodsToWatch( mirroredType.getName(), clientSideTypeMap, topLevelPackage); templateTypeDetailsMap.put( gwtType, getTemplateDetails( dataDictionary, gwtType.getTemplate(), mirrorTypeMap.get(gwtType), moduleName)); if (gwtType.isCreateUiXml()) { dataDictionary = buildMirrorDataDictionary( gwtType, mirroredType, proxy, mirrorTypeMap, clientSideTypeMap, moduleName); final String contents = getTemplateContents(gwtType.getTemplate() + "UiXml", dataDictionary); xmlTemplates.put(gwtType, contents); } } final Map<String, String> xmlMap = new LinkedHashMap<String, String>(); final List<ClassOrInterfaceTypeDetails> typeDetails = new ArrayList<ClassOrInterfaceTypeDetails>(); for (final GwtProxyProperty proxyProperty : clientSideTypeMap.values()) { if (!proxyProperty.isCollection() || proxyProperty.isCollectionOfProxy()) { continue; } TemplateDataDictionary dataDictionary = TemplateDictionary.create(); dataDictionary.setVariable("packageName", GwtPath.MANAGED_UI.packageName(topLevelPackage)); dataDictionary.setVariable( "scaffoldUiPackage", GwtPath.SCAFFOLD_UI.packageName(topLevelPackage)); final JavaType collectionTypeImpl = getCollectionImplementation(proxyProperty.getPropertyType()); addImport(dataDictionary, collectionTypeImpl); addImport(dataDictionary, proxyProperty.getPropertyType()); final String collectionType = proxyProperty.getPropertyType().getSimpleTypeName(); final String boundCollectionType = proxyProperty.getPropertyType().getParameters().get(0).getSimpleTypeName(); dataDictionary.setVariable("collectionType", collectionType); dataDictionary.setVariable("collectionTypeImpl", collectionTypeImpl.getSimpleTypeName()); dataDictionary.setVariable("boundCollectionType", boundCollectionType); final JavaType collectionEditorType = new JavaType( GwtPath.MANAGED_UI.packageName(topLevelPackage) + "." + boundCollectionType + collectionType + "Editor"); typeDetails.add( getTemplateDetails(dataDictionary, "CollectionEditor", collectionEditorType, moduleName)); dataDictionary = TemplateDictionary.create(); dataDictionary.setVariable("packageName", GwtPath.MANAGED_UI.packageName(topLevelPackage)); dataDictionary.setVariable( "scaffoldUiPackage", GwtPath.SCAFFOLD_UI.packageName(topLevelPackage)); dataDictionary.setVariable("collectionType", collectionType); dataDictionary.setVariable("collectionTypeImpl", collectionTypeImpl.getSimpleTypeName()); dataDictionary.setVariable("boundCollectionType", boundCollectionType); addImport(dataDictionary, proxyProperty.getPropertyType()); final String contents = getTemplateContents("CollectionEditor" + "UiXml", dataDictionary); final String packagePath = projectOperations .getPathResolver() .getFocusedIdentifier( Path.SRC_MAIN_JAVA, GwtPath.MANAGED_UI.getPackagePath(topLevelPackage)); xmlMap.put( packagePath + "/" + boundCollectionType + collectionType + "Editor.ui.xml", contents); } return new GwtTemplateDataHolder(templateTypeDetailsMap, xmlTemplates, typeDetails, xmlMap); } private String getRequestMethodCall( final ClassOrInterfaceTypeDetails request, final MemberTypeAdditions memberTypeAdditions) { final String methodName = memberTypeAdditions.getMethodName(); final MethodMetadata requestMethod = MemberFindingUtils.getMethod(request, methodName); String requestMethodCall = memberTypeAdditions.getMethodName(); if (requestMethod != null) { if (INSTANCE_REQUEST .getFullyQualifiedTypeName() .equals(requestMethod.getReturnType().getFullyQualifiedTypeName())) { requestMethodCall = requestMethodCall + "().using"; } } return requestMethodCall; } public List<ClassOrInterfaceTypeDetails> getStaticTemplateTypeDetails( final GwtType type, final String moduleName) { final List<ClassOrInterfaceTypeDetails> templateTypeDetails = new ArrayList<ClassOrInterfaceTypeDetails>(); final TemplateDataDictionary dataDictionary = buildDictionary(type, moduleName); templateTypeDetails.add( getTemplateDetails( dataDictionary, type.getTemplate(), getDestinationJavaType(type, moduleName), moduleName)); return templateTypeDetails; } private String getTemplateContents( final String templateName, final TemplateDataDictionary dataDictionary) { try { final TemplateLoader templateLoader = TemplateResourceLoader.create(); final Template template = templateLoader.getTemplate(templateName); return template.renderToString(dataDictionary); } catch (final TemplateException e) { throw new IllegalStateException(e); } } public ClassOrInterfaceTypeDetails getTemplateDetails( final TemplateDataDictionary dataDictionary, final String templateFile, final JavaType templateType, final String moduleName) { try { final TemplateLoader templateLoader = TemplateResourceLoader.create(); final Template template = templateLoader.getTemplate(templateFile); Validate.notNull(template, "Template required for '" + templateFile + "'"); final String templateContents = template.renderToString(dataDictionary); final String templateId = PhysicalTypeIdentifier.createIdentifier( templateType, LogicalPath.getInstance(Path.SRC_MAIN_JAVA, moduleName)); return typeParsingService.getTypeFromString(templateContents, templateId, templateType); } catch (final Exception e) { throw new IllegalStateException(e); } } private boolean isReadOnly( final String name, final ClassOrInterfaceTypeDetails governorTypeDetails) { final List<String> readOnly = new ArrayList<String>(); final ClassOrInterfaceTypeDetails proxy = gwtTypeService.lookupProxyFromEntity(governorTypeDetails); if (proxy != null) { readOnly.addAll(GwtUtils.getAnnotationValues(proxy, RooJavaType.ROO_GWT_PROXY, "readOnly")); } return readOnly.contains(name); } private boolean isSameBaseType(final JavaType type1, final JavaType type2) { return type1.getFullyQualifiedTypeName().equals(type2.getFullyQualifiedTypeName()); } private void maybeAddImport( final TemplateDataDictionary dataDictionary, final Set<String> importSet, final JavaType type) { if (!importSet.contains(type.getFullyQualifiedTypeName())) { addImport(dataDictionary, type.getFullyQualifiedTypeName()); importSet.add(type.getFullyQualifiedTypeName()); } } private String transformXml(final Document document) throws TransformerException { final Transformer transformer = XmlUtils.createIndentingTransformer(); final DOMSource source = new DOMSource(document); final StreamResult result = new StreamResult(new StringWriter()); transformer.transform(source, result); return result.getWriter().toString(); } }
@Component(immediate = true) @Service public class GwtLocatorMetadataProviderImpl implements GwtLocatorMetadataProvider { // Constants private static final int LAYER_POSITION = LayerType.HIGHEST.getPosition(); // Fields @Reference GwtTypeService gwtTypeService; @Reference LayerService layerService; @Reference MetadataDependencyRegistry metadataDependencyRegistry; @Reference MetadataService metadataService; @Reference PersistenceMemberLocator persistenceMemberLocator; @Reference ProjectOperations projectOperations; @Reference TypeLocationService typeLocationService; @Reference TypeManagementService typeManagementService; protected void activate(ComponentContext context) { metadataDependencyRegistry.registerDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); } protected void deactivate(ComponentContext context) { metadataDependencyRegistry.deregisterDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); } public MetadataItem get(String metadataIdentificationString) { ProjectMetadata projectMetadata = projectOperations.getProjectMetadata(); if (projectMetadata == null) { return null; } ClassOrInterfaceTypeDetails proxy = getGovernor(metadataIdentificationString); if (proxy == null) { return null; } AnnotationMetadata proxyAnnotation = GwtUtils.getFirstAnnotation(proxy, GwtUtils.PROXY_ANNOTATIONS); if (proxyAnnotation == null) { return null; } String locatorType = GwtUtils.getStringValue(proxyAnnotation.getAttribute("locator")); if (!StringUtils.hasText(locatorType)) { return null; } ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy); if (entity == null) { return null; } MethodMetadata idAccessor = persistenceMemberLocator.getIdentifierAccessor(entity.getName()); MethodMetadata versionAccessor = persistenceMemberLocator.getVersionAccessor(entity.getName()); if (idAccessor == null || versionAccessor == null) { return null; } final JavaType idType = GwtUtils.convertPrimitiveType(idAccessor.getReturnType(), true); String locatorIdentifier = PhysicalTypeIdentifier.createIdentifier(new JavaType(locatorType)); ClassOrInterfaceTypeDetailsBuilder locatorBuilder = new ClassOrInterfaceTypeDetailsBuilder(locatorIdentifier); AnnotationMetadataBuilder annotationMetadataBuilder = new AnnotationMetadataBuilder(RooJavaType.ROO_GWT_LOCATOR); annotationMetadataBuilder.addStringAttribute( "value", entity.getName().getFullyQualifiedTypeName()); locatorBuilder.addAnnotation(annotationMetadataBuilder); annotationMetadataBuilder = new AnnotationMetadataBuilder(SpringJavaType.COMPONENT); locatorBuilder.addAnnotation(annotationMetadataBuilder); locatorBuilder.setName(new JavaType(locatorType)); locatorBuilder.setModifier(Modifier.PUBLIC); locatorBuilder.setPhysicalTypeCategory(PhysicalTypeCategory.CLASS); locatorBuilder.addExtendsTypes( new JavaType( GwtUtils.LOCATOR.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(entity.getName(), idType))); locatorBuilder.addMethod(getCreateMethod(locatorIdentifier, entity.getName())); locatorBuilder.addMethod( getFindMethod(locatorBuilder, locatorIdentifier, entity.getName(), idType)); locatorBuilder.addMethod(getDomainTypeMethod(locatorIdentifier, entity.getName())); locatorBuilder.addMethod(getIdMethod(locatorIdentifier, entity.getName(), idAccessor)); locatorBuilder.addMethod(getIdTypeMethod(locatorIdentifier, entity.getName(), idType)); locatorBuilder.addMethod( getVersionMethod(locatorIdentifier, entity.getName(), versionAccessor)); typeManagementService.createOrUpdateTypeOnDisk(locatorBuilder.build()); return null; } private MethodMetadataBuilder getDomainTypeMethod(String declaredById, JavaType targetType) { InvocableMemberBodyBuilder invocableMemberBodyBuilder = InvocableMemberBodyBuilder.getInstance(); invocableMemberBodyBuilder.append("return " + targetType.getSimpleTypeName() + ".class;"); JavaType returnType = new JavaType( JavaType.CLASS.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(targetType)); return new MethodMetadataBuilder( declaredById, Modifier.PUBLIC, new JavaSymbolName("getDomainType"), returnType, invocableMemberBodyBuilder); } private MethodMetadataBuilder getIdMethod( String declaredById, JavaType targetType, MethodMetadata idAccessor) { InvocableMemberBodyBuilder invocableMemberBodyBuilder = InvocableMemberBodyBuilder.getInstance(); invocableMemberBodyBuilder.append( "return " + StringUtils.uncapitalize(targetType.getSimpleTypeName()) + "." + idAccessor.getMethodName() + "();"); MethodMetadataBuilder getIdMethod = new MethodMetadataBuilder( declaredById, Modifier.PUBLIC, new JavaSymbolName("getId"), GwtUtils.convertPrimitiveType(idAccessor.getReturnType(), true), invocableMemberBodyBuilder); getIdMethod.addParameter(StringUtils.uncapitalize(targetType.getSimpleTypeName()), targetType); return getIdMethod; } private MethodMetadataBuilder getVersionMethod( String declaredById, JavaType targetType, MethodMetadata versionAccessor) { InvocableMemberBodyBuilder invocableMemberBodyBuilder = InvocableMemberBodyBuilder.getInstance(); invocableMemberBodyBuilder.append( "return " + StringUtils.uncapitalize(targetType.getSimpleTypeName()) + "." + versionAccessor.getMethodName() + "();"); MethodMetadataBuilder getIdMethodBuilder = new MethodMetadataBuilder( declaredById, Modifier.PUBLIC, new JavaSymbolName("getVersion"), JavaType.OBJECT, invocableMemberBodyBuilder); getIdMethodBuilder.addParameter( StringUtils.uncapitalize(targetType.getSimpleTypeName()), targetType); return getIdMethodBuilder; } private MethodMetadataBuilder getIdTypeMethod( String declaredById, JavaType targetType, JavaType idType) { InvocableMemberBodyBuilder invocableMemberBodyBuilder = InvocableMemberBodyBuilder.getInstance(); invocableMemberBodyBuilder.append("return " + idType.getSimpleTypeName() + ".class;"); JavaType returnType = new JavaType( JavaType.CLASS.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(idType)); return new MethodMetadataBuilder( declaredById, Modifier.PUBLIC, new JavaSymbolName("getIdType"), returnType, invocableMemberBodyBuilder); } private MethodMetadataBuilder getFindMethod( ClassOrInterfaceTypeDetailsBuilder locatorBuilder, String declaredById, JavaType targetType, JavaType idType) { MemberTypeAdditions findMethodAdditions = layerService.getMemberTypeAdditions( declaredById, PersistenceCustomDataKeys.FIND_METHOD.name(), targetType, idType, LAYER_POSITION, new MethodParameter(idType, "id")); InvocableMemberBodyBuilder invocableMemberBodyBuilder = InvocableMemberBodyBuilder.getInstance(); invocableMemberBodyBuilder .append("return ") .append(findMethodAdditions.getMethodCall()) .append(";"); findMethodAdditions.copyAdditionsTo(locatorBuilder, locatorBuilder.build()); MethodMetadataBuilder findMethodBuilder = new MethodMetadataBuilder( declaredById, Modifier.PUBLIC, new JavaSymbolName("find"), targetType, invocableMemberBodyBuilder); JavaType wildEntityType = new JavaType( targetType.getFullyQualifiedTypeName(), 0, DataType.VARIABLE, JavaType.WILDCARD_EXTENDS, null); JavaType classParameterType = new JavaType( JavaType.CLASS.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(wildEntityType)); findMethodBuilder.addParameter("clazz", classParameterType); findMethodBuilder.addParameter("id", idType); return findMethodBuilder; } private MethodMetadataBuilder getCreateMethod(String declaredById, JavaType targetType) { InvocableMemberBodyBuilder invocableMemberBodyBuilder = InvocableMemberBodyBuilder.getInstance(); invocableMemberBodyBuilder.append("return new " + targetType.getSimpleTypeName() + "();"); MethodMetadataBuilder createMethodBuilder = new MethodMetadataBuilder( declaredById, Modifier.PUBLIC, new JavaSymbolName("create"), targetType, invocableMemberBodyBuilder); JavaType wildEntityType = new JavaType( targetType.getFullyQualifiedTypeName(), 0, DataType.VARIABLE, JavaType.WILDCARD_EXTENDS, null); JavaType classParameterType = new JavaType( JavaType.CLASS.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(wildEntityType)); createMethodBuilder.addParameter("clazz", classParameterType); return createMethodBuilder; } public void notify(String upstreamDependency, String downstreamDependency) { ProjectMetadata projectMetadata = projectOperations.getProjectMetadata(); if (projectMetadata == null) { return; } if (MetadataIdentificationUtils.isIdentifyingClass(downstreamDependency)) { Assert.isTrue( MetadataIdentificationUtils.getMetadataClass(upstreamDependency) .equals( MetadataIdentificationUtils.getMetadataClass( PhysicalTypeIdentifier.getMetadataIdentiferType())), "Expected class-level notifications only for PhysicalTypeIdentifier (not '" + upstreamDependency + "')"); ClassOrInterfaceTypeDetails cid = typeLocationService.getTypeForIdentifier(upstreamDependency); boolean processed = false; if (MemberFindingUtils.getAnnotationOfType(cid.getAnnotations(), RooJavaType.ROO_GWT_REQUEST) != null) { ClassOrInterfaceTypeDetails proxy = gwtTypeService.lookupProxyFromRequest(cid); if (proxy != null) { JavaType typeName = PhysicalTypeIdentifier.getJavaType(proxy.getDeclaredByMetadataId()); Path typePath = PhysicalTypeIdentifier.getPath(proxy.getDeclaredByMetadataId()); downstreamDependency = GwtLocatorMetadata.createIdentifier(typeName, typePath); processed = true; } } if (!processed && MemberFindingUtils.getAnnotationOfType(cid.getAnnotations(), RooJavaType.ROO_GWT_PROXY) == null) { boolean found = false; for (ClassOrInterfaceTypeDetails classOrInterfaceTypeDetails : typeLocationService.findClassesOrInterfaceDetailsWithAnnotation( RooJavaType.ROO_GWT_PROXY)) { AnnotationMetadata annotationMetadata = GwtUtils.getFirstAnnotation( classOrInterfaceTypeDetails, GwtUtils.ROO_PROXY_REQUEST_ANNOTATIONS); if (annotationMetadata != null) { AnnotationAttributeValue<?> attributeValue = annotationMetadata.getAttribute("value"); if (attributeValue != null) { String mirrorName = GwtUtils.getStringValue(attributeValue); if (mirrorName != null && cid.getName().getFullyQualifiedTypeName().equals(attributeValue.getValue())) { found = true; JavaType typeName = PhysicalTypeIdentifier.getJavaType( classOrInterfaceTypeDetails.getDeclaredByMetadataId()); Path typePath = PhysicalTypeIdentifier.getPath( classOrInterfaceTypeDetails.getDeclaredByMetadataId()); downstreamDependency = GwtLocatorMetadata.createIdentifier(typeName, typePath); break; } } } } if (!found) { return; } } else if (!processed) { // A physical Java type has changed, and determine what the corresponding local metadata // identification string would have been JavaType typeName = PhysicalTypeIdentifier.getJavaType(upstreamDependency); Path typePath = PhysicalTypeIdentifier.getPath(upstreamDependency); downstreamDependency = GwtLocatorMetadata.createIdentifier(typeName, typePath); } // 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 (metadataDependencyRegistry .getDownstream(upstreamDependency) .contains(downstreamDependency)) { return; } } // We should now have an instance-specific "downstream dependency" that can be processed by this // class Assert.isTrue( MetadataIdentificationUtils.getMetadataClass(downstreamDependency) .equals(MetadataIdentificationUtils.getMetadataClass(getProvidesType())), "Unexpected downstream notification for '" + downstreamDependency + "' to this provider (which uses '" + getProvidesType() + "'"); metadataService.get(downstreamDependency, true); } public String getProvidesType() { return GwtLocatorMetadata.getMetadataIdentifierType(); } private ClassOrInterfaceTypeDetails getGovernor(String metadataIdentificationString) { JavaType governorTypeName = GwtLocatorMetadata.getJavaType(metadataIdentificationString); Path governorTypePath = GwtLocatorMetadata.getPath(metadataIdentificationString); String physicalTypeId = PhysicalTypeIdentifier.createIdentifier(governorTypeName, governorTypePath); return typeLocationService.getTypeForIdentifier(physicalTypeId); } }