/* * Copyright 2013 The Sculptor Project Team, including 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.sculptor.generator.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import org.sculptor.generator.SculptorGeneratorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sculptormetamodel.Application; import sculptormetamodel.Attribute; import sculptormetamodel.BasicType; import sculptormetamodel.CommandEvent; import sculptormetamodel.Consumer; import sculptormetamodel.DataTransferObject; import sculptormetamodel.DomainEvent; import sculptormetamodel.DomainObject; import sculptormetamodel.DomainObjectTypedElement; import sculptormetamodel.Entity; import sculptormetamodel.EnumConstructorParameter; import sculptormetamodel.EnumValue; import sculptormetamodel.Module; import sculptormetamodel.NamedElement; import sculptormetamodel.Operation; import sculptormetamodel.Parameter; import sculptormetamodel.Reference; import sculptormetamodel.Repository; import sculptormetamodel.RepositoryOperation; import sculptormetamodel.Resource; import sculptormetamodel.ResourceOperation; import sculptormetamodel.SculptormetamodelFactory; import sculptormetamodel.Service; import sculptormetamodel.ServiceOperation; import sculptormetamodel.TypedElement; import sculptormetamodel.ValueObject; import sculptormetamodel.impl.SculptormetamodelFactoryImpl; /** * Utilities for code generation and transformation. It is used from templates * and transformations via extensions. */ public class HelperBase { private static final Logger LOG = LoggerFactory.getLogger(HelperBase.class); private PropertiesBase propBase; private PrimitiveTypeMapper primitiveTypeMapper = new PrimitiveTypeMapper(); private Map<String, String> collectionInterfaceTypeMapper = new HashMap<String, String>(); private Map<String, String> collectionImplTypeMapper = new HashMap<String, String>(); @Inject protected void init(PropertiesBase propBase) { this.propBase = propBase; collectionInterfaceTypeMapper.put("list", propBase.getJavaType("List")); collectionInterfaceTypeMapper.put("bag", propBase.getJavaType("Bag")); collectionInterfaceTypeMapper.put("map", propBase.getJavaType("Map")); collectionInterfaceTypeMapper.put("set", propBase.getJavaType("Set")); collectionInterfaceTypeMapper.put(null, propBase.getJavaType("Set")); collectionImplTypeMapper.put("list", propBase.getJavaTypeImpl("List")); collectionImplTypeMapper.put("bag", propBase.getJavaTypeImpl("Bag")); collectionImplTypeMapper.put("map", propBase.getJavaTypeImpl("Map")); collectionImplTypeMapper.put("set", propBase.getJavaTypeImpl("Set")); collectionImplTypeMapper.put(null, propBase.getJavaTypeImpl("Set")); } public static void printEnvironment() { LOG.warn("######################################################"); LOG.warn("# Runtime environment"); LOG.warn("######################################################"); // Print properties LOG.warn("Properties:"); Properties props = System.getProperties(); for (Map.Entry<Object,Object> key : props.entrySet()) { LOG.warn(" " + key.getKey() + " = " + key.getValue()); } LOG.warn("Environment:"); Map<String, String> env = System.getenv(); for (Map.Entry<String,String> key : env.entrySet()) { LOG.warn(" " + key.getKey() + " = " + key.getValue()); } LOG.warn("######################################################"); } private static final Pattern PLACE_HOLDER_PATTERN = Pattern.compile("\\$\\{[^}]*\\}"); public String processPath(String input) { Matcher matcher = PLACE_HOLDER_PATTERN.matcher(input); StringBuffer out = new StringBuffer(); while(matcher.find()) { String match = matcher.group(); String envVar = match.substring(2, match.length() - 1); String replacement = System.getProperty(envVar); if (replacement == null) { replacement = System.getenv(envVar); } matcher.appendReplacement(out, replacement == null ? envVar : replacement); } matcher.appendTail(out); return out.toString(); } public String getDomainPackage(DomainObject domainObject) { if (domainObject instanceof DataTransferObject) { return getDomainPackage((DataTransferObject) domainObject); } if (domainObject instanceof DomainEvent) { return getDomainPackage((DomainEvent) domainObject); } if (domainObject instanceof CommandEvent) { return getDomainPackage((CommandEvent) domainObject); } if (domainObject.getPackage() == null || domainObject.getPackage().equals("")) { return getDomainPackage(domainObject.getModule()); } else { return concatPackage(getBasePackage(domainObject.getModule()), domainObject.getPackage()); } } public String getDomainPackage(DataTransferObject dto) { if (dto.getPackage() == null || dto.getPackage().equals("")) { return getDtoPackage(dto.getModule()); } else { return concatPackage(getBasePackage(dto.getModule()), dto.getPackage()); } } public String getDomainPackage(DomainEvent event) { if (event.getPackage() == null || event.getPackage().equals("")) { return getDomainEventPackage(event.getModule()); } else { return concatPackage(getBasePackage(event.getModule()), event.getPackage()); } } public String getDomainPackage(CommandEvent event) { if (event.getPackage() == null || event.getPackage().equals("")) { return getCommandEventPackage(event.getModule()); } else { return concatPackage(getBasePackage(event.getModule()), event.getPackage()); } } public String getServiceapiPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getServiceInterfacePackage()); } public String getServiceimplPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getServiceImplementationPackage()); } public String getRestPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getRestPackage()); } public String getServiceproxyPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getServiceProxyPackage()); } public String getConsumerPackage(Consumer consumer) { return concatPackage(getBasePackage(consumer.getModule()), propBase.getConsumerPackage()); } public String getXmlMapperPackage(Consumer consumer) { return concatPackage(getBasePackage(consumer.getModule()), propBase.getXmlMapperPackage()); } public String getAccessapiPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getAccessInterfacePackage()); } public String getAccessimplPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getAccessImplementationPackage()); } public String getDomainPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getDomainPackage()); } public String getDtoPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getDtoPackage()); } public String getDomainEventPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getDomainEventPackage()); } public String getCommandEventPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getCommandEventPackage()); } public String getRepositoryimplPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getRepositoryImplementationPackage()); } public String getRepositoryapiPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getRepositoryInterfacePackage()); } public String getExceptionPackage(Module module) { return concatPackage(getBasePackage(module), propBase.getExceptionPackage()); } public String concatPackage(String pkg1, String pkg2) { if (pkg2 == null || pkg2.equals("")) { return pkg1; } return pkg1 + "." + pkg2; } public String getBasePackage(Module module) { String base = module.getBasePackage(); if (base == null) { base = module.getApplication().getBasePackage(); if (module.getName() != null && !module.getName().equals("")) { base += "." + module.getName(); } } return base; } public Collection<RepositoryOperation> distinctOperations(Repository repository) { LinkedHashMap<String, RepositoryOperation> distinctOperations = new LinkedHashMap<String, RepositoryOperation>(); for (RepositoryOperation op : (List<RepositoryOperation>) repository.getOperations()) { String opKey = distinctOperationKey(op); if (!distinctOperations.containsKey(opKey)) { distinctOperations.put(opKey, op); } } return distinctOperations.values(); } private String distinctOperationKey(RepositoryOperation op) { StringBuilder buf = new StringBuilder(); buf.append(op.getName()); if (op.isDelegateToAccessObject()) { buf.append("=>"); } if (op.getAccessObjectName() != null) { buf.append(op.getAccessObjectName()); } return buf.toString(); } public Collection<String> exceptions(Operation op) { String throwsString = op.getThrows(); if (throwsString == null || throwsString.equals("")) { return new ArrayList<String>(); } String[] exceptions = throwsString.split(","); Module module = operationModule(op); for (int i = 0; i < exceptions.length; i++) { exceptions[i] = fullyQualifiedException(exceptions[i], module); } return Arrays.asList(exceptions); } private String fullyQualifiedException(String e, Module module) { String mappedName = getJavaType(e.trim()).trim(); if (isGeneratedException(mappedName)) { return getExceptionPackage(module) + "." + mappedName; } else { return mappedName; } } private String fullyQualifiedThrows(Operation op) { Collection<String> exceptions = exceptions(op); Module module = operationModule(op); StringBuffer sb = new StringBuffer(); for (String exc : exceptions) { if (sb.length() > 0) { sb.append(","); } sb.append(fullyQualifiedException(exc, module)); } return sb.toString(); } private boolean isGeneratedException(String e) { return e.indexOf('.') == -1; } public Collection<String> getGeneratedExceptions(Operation op) { String throwsString = op.getThrows(); if (throwsString == null || throwsString.equals("")) { return new ArrayList<String>(); } String[] exceptions = throwsString.split(","); List<String> generatedExceptions = new ArrayList<String>(); for (int i = 0; i < exceptions.length; i++) { String e = exceptions[i].trim(); String mappedName = getJavaType(e).trim(); if (isGeneratedException(mappedName)) { generatedExceptions.add(mappedName); } } return generatedExceptions; } public String getTypeName(Reference ref) { return getDomainPackage(ref.getTo()) + "." + ref.getTo().getName(); } public String getTypeName(TypedElement element) { String type = getJavaTypeOrVoid(element.getType()); return surroundWithCollectionType(type, element, false); } public String getTypeName(DomainObjectTypedElement element) { return getTypeName(element, true); } public String getTypeName(DomainObjectTypedElement element, boolean surroundWithCollectionType) { String typeName = getJavaTypeOrVoid(element.getType()); String type = typeName; String domainObjectTypeName = null; if (element.getDomainObjectType() != null) { domainObjectTypeName = getJavaTypeOrVoid(getDomainPackage(element.getDomainObjectType()) + "." + element.getDomainObjectType().getName()); type = domainObjectTypeName; } if (typeName != null && !typeName.equals("void") && domainObjectTypeName != null && !domainObjectTypeName.equals("void")) { type = typeName + "<" + domainObjectTypeName + ">"; } return (surroundWithCollectionType ? surroundWithCollectionType(type, element, false) : type); } public String getImplTypeName(TypedElement element) { String type = getJavaTypeImpl(element.getType()); return surroundWithCollectionType(type, element, true); } private String surroundWithCollectionType(String type, TypedElement typedElement, boolean collectionImpl) { if (typedElement.getCollectionType() == null || typedElement.getCollectionType().equals("") || type == null || type.equals("") || type.equals("void")) { return type; } else { String mappedCollectionType = (collectionImpl ? getJavaTypeImpl(typedElement.getCollectionType()) : getJavaType(typedElement.getCollectionType())); if (typedElement.getCollectionType().equals("Map")) { String keyType = getMapKeyType((DomainObjectTypedElement) typedElement); mappedCollectionType += "<" + keyType + ", " + type + ">"; } else { mappedCollectionType += "<" + type + ">"; } return mappedCollectionType; } } private String getMapKeyType(DomainObjectTypedElement element) { DomainObject domainObject = element.getMapKeyDomainObjectType(); if (domainObject != null) { return getJavaTypeOrVoid(getDomainPackage(domainObject) + "." + domainObject.getName()); } String type = element.getMapKeyType(); if (type != null) { return type; } return "Object"; } private String getJavaTypeOrVoid(String type) { if (type == null || type.equals("")) { return "void"; } return getJavaType(type); } public String getJavaType(String modelType) { String javaType = propBase.getJavaType(modelType); if (javaType == null) { return modelType; } else { return javaType; } } private String getJavaTypeImpl(String modelType) { String javaType = propBase.getJavaTypeImpl(modelType); if (javaType == null) { return getJavaType(modelType); } else { return javaType; } } /** * Java interface for the collection type. * * @see #getCollectionType(sculptormetamodel.Reference) */ public String getCollectionInterfaceType(Reference ref) { String collectionType = getCollectionType(ref); return getCollectionInterfaceType(collectionType); } private String getCollectionInterfaceType(String collectionType) { String result = collectionInterfaceTypeMapper.get(collectionType); if (result == null) { result = collectionInterfaceTypeMapper.get(null); } return result; } /** * Java implementation class for the collection type. * * @see #getCollectionType(sculptormetamodel.Reference) */ public String getCollectionImplType(Reference ref) { String collectionType = getCollectionType(ref); return getCollectionImplType(collectionType); } private String getCollectionImplType(String collectionType) { String result = collectionImplTypeMapper.get(collectionType); if (result == null) { result = collectionImplTypeMapper.get(null); } return result; } /** * Collection type can be set, list, bag or map. It corresponds to the * Hibernate collection types. */ public String getCollectionType(Reference ref) { String type = ref.getCollectionType(); return (type == null ? "set" : type.toLowerCase()); } public String getCollectionType(Attribute attr) { String type = attr.getCollectionType(); return (type == null ? "set" : type.toLowerCase()); } /** * Get-accessor method name of a property, according to JavaBeans naming * conventions. */ public String getGetAccessor(TypedElement e, String prefix) { String capName = toFirstUpper(e.getName()); if (prefix != null) { capName = toFirstUpper(prefix) + capName; } // Note that Boolean object type is not named with is prefix (according // to java beans spec) String result = isBooleanPrimitiveType(e) ? "is" + capName : "get" + ("Class".equals(capName) ? "Class_" : capName); return result; } /** * First character to upper case. */ public String toFirstUpper(String name) { if (name.length() == 0) { return name; } else { return name.substring(0, 1).toUpperCase() + name.substring(1); } } /** * First character to lower case. */ public String toFirstLower(String name) { if (name.length() == 0) { return name; } else { return name.substring(0, 1).toLowerCase() + name.substring(1); } } /** * Gets a substring between the begin and end boundaries * * @param string * original string * @param begin * start boundary * @param end * end boundary * @return substring between boundaries */ public String substringBetween(String string, String begin, String end) { return substringBetween(string, begin, end, false); } /** * Gets a substring between the begin and end boundaries * * @param string * original string * @param begin * start boundary * @param end * end boundary * @param includeBoundaries * include the boundaries in substring * @return substring between boundaries */ public String substringBetween(String string, String begin, String end, boolean includeBoundaries) { if (string == null || begin == null || end == null) { return null; } int startPos = string.indexOf(begin); if (startPos != -1) { if (includeBoundaries) startPos = startPos - begin.length(); int endPos = string.lastIndexOf(end); if (endPos != -1) { if (includeBoundaries) endPos = endPos + end.length(); return string.substring(startPos + begin.length(), endPos); } } return null; } /** * Gets the substring before a given pattern * * @param string * original string * @param pattern * pattern to check * @return substring before the pattern */ public String substringBefore(String string, String pattern) { if (string == null || pattern == null) { return string; } int pos = string.indexOf(pattern); if (pos != -1) { return string.substring(0, pos); } return null; } private boolean isBooleanPrimitiveType(TypedElement e) { if (e.getType() == null) { return false; } return "boolean".equals(getTypeName(e)); } public String getRepositoryBaseName(Repository repository) { if (!repository.getName().endsWith("Repository")) { throw new SculptorGeneratorException("Expect name of repository argument to end with \"Repository\""); } String baseName = repository.getName().substring(0, repository.getName().length() - "Repository".length()); return baseName; } public List<?> addServiceContextParameter(ServiceOperation operation) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Parameter ctxParameter = factory.createParameter(); ctxParameter.setName("ctx"); ctxParameter.setType(propBase.getServiceContextClass()); operation.getParameters().add(0, ctxParameter); return operation.getParameters(); } public Entity addAuditable(Entity entity) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; boolean useJoda = propBase.getBooleanProperty("generate.auditable.joda"); String timestampType = useJoda ? "DateTime" : "java.util.Date"; if (!hasElement("createdDate", entity.getAttributes())) { Attribute createdDate = factory.createAttribute(); createdDate.setName("createdDate"); createdDate.setType(timestampType); createdDate.setNullable(true); entity.getAttributes().add(createdDate); } if (!hasElement("createdBy", entity.getAttributes())) { Attribute createdBy = factory.createAttribute(); createdBy.setName("createdBy"); createdBy.setType("String"); createdBy.setLength("50"); createdBy.setNullable(true); entity.getAttributes().add(createdBy); } if (!hasElement("lastUpdated", entity.getAttributes())) { Attribute lastUpdated = factory.createAttribute(); lastUpdated.setName("lastUpdated"); lastUpdated.setType(timestampType); lastUpdated.setNullable(true); entity.getAttributes().add(lastUpdated); } if (!hasElement("lastUpdatedBy", entity.getAttributes())) { Attribute lastUpdatedBy = factory.createAttribute(); lastUpdatedBy.setName("lastUpdatedBy"); lastUpdatedBy.setType("String"); lastUpdatedBy.setLength("50"); lastUpdatedBy.setNullable(true); entity.getAttributes().add(lastUpdatedBy); } return entity; } private boolean hasElement(String name, List<? extends NamedElement> namedElements) { for (NamedElement each : namedElements) { if (name.equals(each.getName())) { return true; } } return false; } public DomainObject addVersionAttribute(DomainObject domainObject) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Attribute version = factory.createAttribute(); version.setName("version"); version.setType("Long"); version.setNullable(false); domainObject.getAttributes().add(version); return domainObject; } public DomainObject addIdAttributeImpl(DomainObject domainObject) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Attribute id = factory.createAttribute(); id.setName("id"); id.setType(propBase.getIdType()); domainObject.getAttributes().add(0, id); return domainObject; } public DomainObject addUuidAttribute(DomainObject domainObject) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Attribute uuid = factory.createAttribute(); uuid.setName("uuid"); uuid.setType("UUID"); domainObject.getAttributes().add(uuid); return domainObject; } public DomainObject addRepository(DomainObject domainObject) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Repository repository = factory.createRepository(); repository.setName(domainObject.getName() + "Repository"); repository.setGapClass(propBase.getBooleanProperty("generate.gapClass")); domainObject.setRepository(repository); return domainObject; } public Repository addRepositoryScaffoldOperations(Repository repository) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Set<String> existingOperations = new HashSet<String>(); for (RepositoryOperation op : repository.getOperations()) { existingOperations.add(op.getName()); } for (String operationName : propBase.scaffoldOperations()) { if (!existingOperations.contains(operationName)) { RepositoryOperation op = factory.createRepositoryOperation(); op.setName(operationName); repository.getOperations().add(op); } } return repository; } public Module addService(Module module, String serviceName) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Service service = factory.createService(); service.setName(serviceName); service.setGapClass(propBase.getBooleanProperty("generate.gapClass")); module.getServices().add(service); return module; } public Service addServiceScaffoldOperations(Service service, Repository delegateRepository) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Set<String> existingOperations = new HashSet<String>(); for (ServiceOperation op : (List<ServiceOperation>) service.getOperations()) { existingOperations.add(op.getName()); } for (String operationName : propBase.scaffoldOperations()) { if (!existingOperations.contains(operationName)) { // note that we add one ServiceOperation for each // RepositoryOperation with this name, // there may be several with same name for (RepositoryOperation repositoryOp : delegateRepository.getOperations()) { if (repositoryOp.getName().equals(operationName)) { ServiceOperation op = factory.createServiceOperation(); op.setName(operationName); service.getOperations().add(op); op.setDelegate(repositoryOp); } } } } return service; } public Resource addResourceScaffoldOperations(Resource resource, Service delegateService) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Set<String> existingOperations = new HashSet<String>(); for (ResourceOperation op : resource.getOperations()) { existingOperations.add(op.getName()); } for (String operationName : propBase.restScaffoldOperations()) { if (!existingOperations.contains(operationName)) { String serviceOperationName = propBase.restServiceDelegateOperation(operationName); ServiceOperation serviceOp; if (serviceOperationName == null || delegateService == null) { serviceOp = null; } else { serviceOp = operation(delegateService, serviceOperationName); } ResourceOperation op = factory.createResourceOperation(); op.setName(operationName); resource.getOperations().add(op); op.setDelegate(serviceOp); } } return resource; } private ServiceOperation operation(Service service, String operationName) { for (ServiceOperation serviceOp : (List<ServiceOperation>) service.getOperations()) { if (serviceOp.getName().equals(operationName)) { return serviceOp; } } return null; } /** * Fill in parameters and return values for operations that delegate to * Service. */ public void addDefaultValues(Resource resource) { for (ResourceOperation op : resource.getOperations()) { addDefaultValues(op); } } /** * Fill in parameters and return values for operations that delegate to * Repository. */ public void addDefaultValues(Service service) { for (ServiceOperation op : (List<ServiceOperation>) service.getOperations()) { addDefaultValues(op); } } /** * Copy values from delegate RepositoryOperation to this ServiceOperation */ private void addDefaultValues(ServiceOperation operation) { if (operation.getDelegate() != null) { copyFromDelegate(operation, operation.getDelegate(), true); } else if (operation.getServiceDelegate() != null) { // make sure that the service delegate has been populated first addDefaultValues(operation.getServiceDelegate()); // recursive call // (circular dependencies not allowed) copyFromDelegate(operation, operation.getServiceDelegate(), true); } } /** * Copy values from delegate ServiceOperation to this ResourceOperation */ private void addDefaultValues(ResourceOperation operation) { if (operation.getDelegate() != null) { copyFromDelegate(operation, operation.getDelegate(), false); } } private void copyFromDelegate(Operation operation, Operation delegate, boolean inclServiceContext) { if (operation.getParameters().isEmpty()) { SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; String serviceContextClass = propBase.getServiceContextClass(); for (Parameter delegateParam : (List<Parameter>) delegate.getParameters()) { if (!inclServiceContext && serviceContextClass.equals(delegateParam.getType())) { continue; } Parameter param = factory.createParameter(); param.setName(delegateParam.getName()); param.setDomainObjectType(delegateParam.getDomainObjectType()); param.setType(delegateParam.getType()); param.setCollectionType(delegateParam.getCollectionType()); param.setMapKeyType(delegateParam.getMapKeyType()); operation.getParameters().add(param); } } if (operation.getType() == null || operation.getType().equals("")) { operation.setType(delegate.getType()); } if (operation.getDomainObjectType() == null) { operation.setDomainObjectType(delegate.getDomainObjectType()); } if (operation.getCollectionType() == null || operation.getCollectionType().equals("")) { operation.setCollectionType(delegate.getCollectionType()); } if (operation.getMapKeyType() == null || operation.getMapKeyType().equals("")) { operation.setMapKeyType(delegate.getMapKeyType()); } if (operation.getThrows() == null || operation.getThrows().equals("")) { if (operationModule(operation).equals(operationModule(delegate))) { operation.setThrows(delegate.getThrows()); } else { // delegation between modules requires fully qualified exception // class names operation.setThrows(fullyQualifiedThrows(delegate)); } } } private Module operationModule(Operation op) { if (op instanceof RepositoryOperation) { return ((RepositoryOperation) op).getRepository().getAggregateRoot().getModule(); } else if (op instanceof ServiceOperation) { return ((ServiceOperation) op).getService().getModule(); } else if (op instanceof ResourceOperation) { return ((ResourceOperation) op).getResource().getModule(); } else { throw new SculptorGeneratorException("Unsupported operation type: " + op.getClass().getName()); } } /** * Throws a {@link SculptorGeneratorException} to stop the generation with an error message. * * @param msg * message to log */ public void error(String msg) { throw new SculptorGeneratorException(msg); } public Long currentTimeMillis() { return System.currentTimeMillis(); } public String formatJavaDoc(String doc) { if (doc == null || doc.trim().equals("")) { return ""; } StringBuffer sb = new StringBuffer(); sb.append("/**\n"); String s = doc.trim(); String[] rows = s.split("\n"); for (int i = 0; i < rows.length; i++) { sb.append(" * ").append(rows[i].trim()).append("\n"); } sb.append(" */"); return sb.toString(); } public Set<Reference> getAllReferences(Application application) { Set<Reference> all = new HashSet<Reference>(); for (DomainObject d : getAllDomainObjects(application)) { for (Reference ref : (List<Reference>) d.getReferences()) { if (!all.contains(ref.getOpposite())) { all.add(ref); } } } return all; } private List<DomainObject> getAllDomainObjects(Application application) { List<DomainObject> all = new ArrayList<DomainObject>(); List<Module> modules = application.getModules(); for (Module m : modules) { for (DomainObject d : (List<DomainObject>) m.getDomainObjects()) { all.add(d); } } List<DomainObject> result = sortByName(all); return result; } public boolean isPrimitiveType(String typeName) { return primitiveTypeMapper.isPrimitiveType(typeName); } public String getObjectTypeName(String typeName) { return primitiveTypeMapper.mapPrimitiveType2ObjectTypeName(typeName); } public sculptormetamodel.Enum modifyEnum(sculptormetamodel.Enum enumObject) { modifyEnumImplicitAttribute(enumObject); modifyEnumConstructorParameters(enumObject); return enumObject; } private void modifyEnumImplicitAttribute(sculptormetamodel.Enum enumObject) { if (!enumObject.getAttributes().isEmpty()) { return; } EnumValue first = (EnumValue) enumObject.getValues().get(0); if (first.getParameters().isEmpty()) { return; } EnumConstructorParameter param = (EnumConstructorParameter) first.getParameters().get(0); SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE; Attribute value = factory.createAttribute(); value.setName("value"); value.setType(resolveEnumImplicitAttributeType(param)); value.setNaturalKey(true); enumObject.getAttributes().add(value); } private String resolveEnumImplicitAttributeType(EnumConstructorParameter param) { if (isEnclosedWithQuotes(param.getValue())) { return "String"; } try { Integer.parseInt(param.getValue()); return "int"; } catch (RuntimeException e) { // it wasn't an int } return "String"; } private void modifyEnumConstructorParameters(sculptormetamodel.Enum enumObject) { if (enumObject.getAttributes().isEmpty()) { return; } for (EnumValue value : (List<EnumValue>) enumObject.getValues()) { Iterator<EnumConstructorParameter> iter = value.getParameters().iterator(); for (int i = 0; iter.hasNext(); i++) { EnumConstructorParameter param = iter.next(); Attribute att = (Attribute) enumObject.getAttributes().get(i); if (getTypeName(att).equals("String") && !isEnclosedWithQuotes(param.getValue())) { param.setValue("\"" + param.getValue() + "\""); } } } } private boolean isEnclosedWithQuotes(String value) { return value.startsWith("\"") && value.endsWith("\""); } /** * Handles Validation Annotations for DomainObjects. * * @param domainObject * @return validation annotations */ public String getValidationAnnotations(DomainObject domainObject) { return handleValidationAnnotations(domainObject.getValidate()); } /** * Handles Validation Annotations for Attributes. * * @param attribute * @return validation annotations */ public String getValidationAnnotations(Attribute attribute) { return handleValidationAnnotations(attribute.getValidate()); } /** * Handles Validation Annotations for References. * * @param reference * @return validation annotations */ public String getValidationAnnotations(Reference reference) { return handleValidationAnnotations(reference.getValidate()); } /** * Parses the given validation string and tries to map annotations from * properties. * * @param validate * String with validation information * @return validation annotations */ private String handleValidationAnnotations(String validate) { if (validate == null) return ""; if (validate.length() > 15) { @SuppressWarnings("unused") boolean baa = true; } // parsing the validate string is simple text replacement validate = validate.replaceAll("&&", " "); validate = validate.replaceAll("'", "\""); for (Map.Entry<String, String> entry : propBase.validationAnnotationDefinitions().entrySet()) { String firstChar = entry.getKey().substring(0, 1); String keyPattern = "[" + firstChar.toUpperCase() + firstChar.toLowerCase() + "]" + entry.getKey().substring(1); validate = validate.replaceAll("@" + keyPattern, "@" + entry.getValue()); } return validate.trim(); } /** * Handles all validation annotations with multiple parameters (Range, Size, * ...). * * @param annotation * the name of the annotation * @param parameterNames * the parameter names * @param parameters * the parameter values * @param validate * the validate string * @return annotation validation string */ public String handleParameterizedAnnotation(String annotation, String parameterNames, String parameters, String validate) { if (parameters == null) return ""; if (parameterNames == null) return ""; // validate contains range if (validate != null && validate.toLowerCase().matches(".*@" + annotation.toLowerCase() + ".*")) return ""; String result = " @" + annotation; // if validate contains any given parameter name, add complete // annotation String[] paramNames = parameterNames.split(","); for (String paramName : paramNames) { if (parameters.toLowerCase().matches(".*" + paramName + ".*")) { result += "(" + parameters + ")"; return result + " "; } } // setting parameters String[] params = parameters.split(","); result += "("; for (int i = 0; i < params.length; i++) { if (paramNames[i] != null) { if (i > 0) result += ","; result += paramNames[i] + "=" + params[i]; } } result += ")"; return result + " "; } /** * Handles all simple validation annotations (Max, Min, ...). * * @param annotation * the name of the annotation * @param value * the parameter values * @param validate * the validate string * @return annotation validation string */ public String handleSimpleAnnotation(String annotation, String value, String validate) { if (value == null) return ""; // if validate contains annotation, do nothing if (validate != null && validate.toLowerCase().matches(".*@" + annotation.toLowerCase() + ".*")) return ""; String result = " @" + annotation; // if validate contains named annotation parameters if (value.toLowerCase().matches(".*value.*") || value.toLowerCase().matches(".*message.*")) { result += "(" + value + ") "; return result + " "; } // a simple annotation only has parameters value and message String[] params = value.split(","); if (params.length == 1) result += "(" + params[0] + ")"; if (params.length == 2) result += "(value=" + params[0] + ", message=" + params[1] + ")"; return result + " "; } /** * Handles all boolean validation annotations (Future, Past, Email, ...). * * @param annotation * the name of the annotation * @param value * annotation is set or not * @param validate * the validate string * @return annotation validation string */ public String handleBooleanAnnotation(String annotation, Boolean value, String message, String validate) { if (!Boolean.TRUE.equals(value)) return ""; // if validate contains annotation, do nothing if (validate != null && validate.toLowerCase().matches(".*@" + annotation.toLowerCase() + ".*")) return ""; String result = " @" + annotation; // set message if not set if (message != null) { result += "(" + (message.toLowerCase().matches(".*message.*") ? "" : "message=") + message + ")"; } return result + " "; } static <T extends NamedElement> List<T> sortByName(List<T> list) { List<T> result = new ArrayList<T>(list); Collections.sort(result, new NameSorter()); return result; } private static class NameSorter implements Comparator<NamedElement> { public int compare(NamedElement obj1, NamedElement obj2) { if (obj1 == null || obj1.getName() == null) { return -1; } if (obj2 == null || obj2.getName() == null) { return 1; } return obj1.getName().compareTo(obj2.getName()); } } public String formatAnnotationParameters(List<Object> list) { return formatAnnotationParameters(null, list); } public String formatAnnotationParameters(String annotation, List<Object> list) { Map<String, Object> collected = new LinkedHashMap<String, Object>(); for (int i = 0; i < list.size(); i += 3) { Boolean condition = (Boolean) list.get(i); if (condition) { String key = (String) list.get(i + 1); if (key.equals("")) { key = "__" + i; } Object value = list.get(i + 2); collected.put(key, value); } } if (collected.isEmpty()) { return ""; } StringBuilder result = new StringBuilder(); if (annotation != null) { result.append(annotation).append("("); } for (Iterator<Entry<String, Object>> iter = collected.entrySet().iterator(); iter.hasNext();) { Entry<String, Object> each = iter.next(); if (!each.getKey().startsWith("__")) { result.append(each.getKey()).append("="); } result.append(each.getValue()); if (iter.hasNext()) { result.append(", "); } } if (annotation != null) { result.append(")"); } return result.toString(); } public String getHintImpl(String hint, String parameter) { return getHintImpl(hint, parameter, ",;"); } // need to specify the separator in case the hint value contains a ',' // TODO: very quick solution public String getHintImpl(String hint, String parameter, String separator) { if (hint == null) { return null; } if (hint.indexOf(parameter) == -1) { return null; } String[] split = hint.split("[" + separator + "]"); split = trim(split); for (int i = 0; i < split.length; i++) { int indexOfEq = split[i].indexOf("="); if (indexOfEq == -1) { if (split[i].equals(parameter)) { return ""; } } else { if (split[i].substring(0, indexOfEq).trim().equals(parameter)) { return split[i].substring(indexOfEq + 1).trim(); } } } // not found return null; } public boolean hasHintImpl(String hint, String parameter) { return getHintImpl(hint, parameter) != null; } public void addHint(NamedElement element, String hint) { addHint(element, hint, ","); } public void addHint(NamedElement element, String hint, String separator) { String hintKey; int indexOfEq = hint.indexOf("="); if (indexOfEq == -1) { hintKey = hint; } else { hintKey = hint.substring(0, indexOfEq).trim(); } if (hasHintImpl(element.getHint(), hintKey)) { return; } String fullHintStr = element.getHint(); if (fullHintStr == null || fullHintStr.equals("")) { fullHintStr = hint; } else { fullHintStr += separator + " " + hint; } element.setHint(fullHintStr); } private String[] trim(String[] array) { String[] result = new String[array.length]; for (int i = 0; i < array.length; i++) { result[i] = array[i].trim(); } return result; } public List<Object> filterValues(List<Object> keys, List<Object> values) { List<Object> result = new ArrayList<Object>(); Set<Object> used = new HashSet<Object>(); for (int i = 0; i < keys.size(); i++) { if (!used.contains(keys.get(i))) { result.add(values.get(i)); used.add(keys.get(i)); } } return result; } public String toSeparatedString(List<?> values, String separator) { StringBuilder result = new StringBuilder(); for (Object each : values) { if (each == null) { continue; } if (result.length() > 0) { result.append(separator); } result.append(String.valueOf(each)); } return result.toString(); } public boolean isEntityOrPersistentValueObject(DomainObject d) { if ((d instanceof BasicType) || (d instanceof sculptormetamodel.Enum)) { return false; } return isPersistent(d); } protected boolean isPersistent(DomainObject domainObject) { if (domainObject instanceof Entity) { return true; } else if (domainObject instanceof ValueObject) { ValueObject vo = (ValueObject) domainObject; return vo.isPersistent(); } else { return false; } } public List<Object> addFirst(List<Object> list, Object values) { list.add(0, values); return list; } public String replaceParamNamePlaceholders(String str, Operation op) { if (str.indexOf("${p") == -1) { // nothing to replace return str; } String serviceContextClass = propBase.getServiceContextClass(); int i = 0; String result = str; for (Parameter each : (Iterable<Parameter>) op.getParameters()) { if (serviceContextClass.equals(getTypeName(each))) { continue; } result = result.replaceAll("\\$\\{p" + i + "}", each.getName()); i++; } return result; } public String replacePlaceholder(String str, String placeholder, String replacement) { // Strange, regexp is not cooperating with me for this, so I use // substring instead int i = str.indexOf(placeholder); if (i == -1) { return str; } String result = str.substring(0, i) + replacement + str.substring(i + placeholder.length()); return result; } private static final HashMap<String, Integer> counters = new HashMap<String, Integer>(); public String counterInc(String counter) { Integer i = counters.get(counter); i = i != null ? i + 1 : 0; counters.put(counter, i); return i.toString(); } public void counterReset(String counter, Integer initValue) { counters.put(counter, initValue); } public String getReferencePathFromReturnType(RepositoryOperation op) { DomainObject returnType = op.getDomainObjectType(); if (returnType == null) { return null; } DomainObject aggregatRoot = op.getRepository().getAggregateRoot(); for (Reference reference : (List<Reference>) aggregatRoot.getReferences()) { if (reference.getTo() == returnType) { return reference.getName(); } } // TODO: look deeper in the reference tree (without cyclic references) for (Reference reference : (List<Reference>) aggregatRoot.getReferences()) { for (Reference reference2 : (List<Reference>) reference.getTo().getReferences()) { if (reference2.getTo() == returnType) { return reference.getName() + "." + reference2.getName(); } } } return null; } public String toConditionalCriteria(String condition, String root) { return new QueryConverter.ConditionalCriteriaStrategy(condition,root).toQueryDsl(); } }