/*
* Copyright 2007 The Fornax 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.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.sculptor.generator.ext.Helper;
import sculptormetamodel.Attribute;
import sculptormetamodel.DomainObject;
import sculptormetamodel.Parameter;
import sculptormetamodel.Reference;
import sculptormetamodel.RepositoryOperation;
import sculptormetamodel.SculptormetamodelFactory;
import sculptormetamodel.impl.SculptormetamodelFactoryImpl;
public class GenericAccessObjectManager {
private final Map<String, GenericAccessObjectStrategy> genericAccessObjectStrategies = new HashMap<String, GenericAccessObjectStrategy>();
private PropertiesBase propBase;
private HelperBase helperBase;
@Inject
private Helper helper;
@Inject
protected void init(PropertiesBase propBase, HelperBase helperBase) {
this.propBase = propBase;
this.helperBase = helperBase;
initGenericAccessObjectStrategies();
}
private void initGenericAccessObjectStrategies() {
// By default the NullStrategy is used if only the access object class
// is defined
NullStrategy nullStrategy = new NullStrategy();
for (String propertyName : propBase.getPropertyNames()) {
if (propertyName.startsWith("framework.accessapi.")) {
String key = propertyName.split("\\.")[2]; // last part
if (key.endsWith("Access")) {
key = key.substring(0, key.length() - "Access".length());
key = helperBase.toFirstLower(key);
genericAccessObjectStrategies.put(key, nullStrategy);
}
}
if (propertyName.startsWith("framework.accessimpl.")) {
String key = propertyName.split("\\.")[2]; // last part
if (key.endsWith("AccessImpl")) {
key = key.substring(0, key.length() - "AccessImpl".length());
key = helperBase.toFirstLower(key);
genericAccessObjectStrategies.put(key, nullStrategy);
}
}
}
for (String propertyName : propBase.getPropertyNames()) {
if (propertyName.startsWith("genericAccessObjectStrategy.")) {
String key = propertyName.split("\\.")[1]; // last part
String propertyValue = propBase.getProperty(propertyName);
if (propertyValue == null || propertyValue.trim().equals("")) {
genericAccessObjectStrategies.put(key, nullStrategy);
} else {
GenericAccessObjectStrategy strategy = (GenericAccessObjectStrategy) FactoryHelper
.newInstanceFromName(this, propertyValue);
genericAccessObjectStrategies.put(key, strategy);
}
}
}
}
protected Map<String, GenericAccessObjectStrategy> getGenericAccessObjectStrategies() {
return genericAccessObjectStrategies;
}
public boolean isGenericAccessObject(RepositoryOperation op) {
return genericAccessObjectStrategies.containsKey(op.getName());
}
public boolean isPersistentClassConstructor(RepositoryOperation op) {
GenericAccessObjectStrategy strategy = genericAccessObjectStrategies.get(op.getName());
return strategy.isPersistentClassConstructor();
}
/**
* Get the generic type declaration for generic access objects.
*/
public String getGenericType(RepositoryOperation op) {
GenericAccessObjectStrategy strategy = genericAccessObjectStrategies.get(op.getName());
if (strategy == null) {
return "";
} else {
return strategy.getGenericType(op);
}
}
public GenericAccessObjectStrategy getStrategy(String operationName) {
return genericAccessObjectStrategies.get(operationName);
}
public abstract class AbstractGenericAccessObjectStrategy implements GenericAccessObjectStrategy {
protected void addParameter(RepositoryOperation operation, String type, String name) {
Parameter param = createParameter(type, name);
operation.getParameters().add(param);
}
public abstract boolean isPersistentClassConstructor();
public abstract String getGenericType(RepositoryOperation operation);
public abstract void addDefaultValues(RepositoryOperation operation);
protected void addParameterFirst(RepositoryOperation operation, String type, String name) {
Parameter param = createParameter(type, name);
operation.getParameters().add(0, param);
}
protected Parameter createParameter(String type, String name) {
SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE;
Parameter param = factory.createParameter();
param.setName(name);
param.setType(type);
return param;
}
protected void addDefaultCollectionType(RepositoryOperation operation) {
if (operation.getCollectionType() == null || operation.getCollectionType().equals("")) {
operation.setCollectionType("List");
}
}
protected void addDefaultDomainObjectType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null) {
operation.setDomainObjectType(operation.getRepository().getAggregateRoot());
}
}
protected String aggregateRootClassName(RepositoryOperation operation) {
DomainObject aggregateRoot = operation.getRepository().getAggregateRoot();
String pkg = helperBase.getDomainPackage(aggregateRoot);
return pkg + "." + aggregateRoot.getName();
}
protected void addDefaultAggregateRootParameter(RepositoryOperation operation, String name) {
if (operation.getParameters().isEmpty()) {
SculptormetamodelFactory factory = SculptormetamodelFactoryImpl.eINSTANCE;
Parameter param = factory.createParameter();
param.setName(name);
param.setDomainObjectType(operation.getRepository().getAggregateRoot());
operation.getParameters().add(param);
}
}
protected boolean hasParameter(RepositoryOperation operation, String name) {
for (Parameter each : (Iterable<Parameter>) operation.getParameters()) {
if (each.getName().equals(name)) {
return true;
}
}
return false;
}
protected void addNotFoundException(RepositoryOperation operation) {
if (propBase.getBooleanProperty("generate.NotFoundException")
&& (operation.getThrows() == null || operation.getThrows().equals(""))) {
String objectNotFoundExc = operation.getRepository().getAggregateRoot().getName() + "NotFoundException";
operation.setThrows(objectNotFoundExc);
}
}
}
public class NullStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
}
@Override
public String getGenericType(RepositoryOperation operation) {
DomainObject aggregateRoot = operation.getRepository().getAggregateRoot();
String aggregateRootName = helperBase.getDomainPackage(aggregateRoot) + "." + aggregateRoot.getName();
return "<" + aggregateRootName + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return false;
}
}
private static String findDslDeclaredIdType(DomainObject domainObject) {
String dslDeclaredIdType = null;
List<Attribute> attributes = (List<Attribute>) domainObject.getAttributes();
for (int i = 0; attributes != null && i < attributes.size(); i++) {
Attribute attribute = attributes.get(i);
if (attribute.getName().equals("id")) {
dslDeclaredIdType = attribute.getType();
break;
}
}
return dslDeclaredIdType;
}
public class FindByIdStrategy extends AbstractGenericAccessObjectStrategy {
private final PrimitiveTypeMapper primitiveTypeMapper = new PrimitiveTypeMapper();
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()) {
String dslDeclaredIdType = findDslDeclaredIdType(operation.getRepository().getAggregateRoot());
String idType = propBase.getIdType();
String javaType = propBase.getJavaType(idType);
// id declared in dsl has precedence
if (dslDeclaredIdType != null) {
javaType = dslDeclaredIdType;
} else if (javaType == null) {
javaType = idType;
}
addParameter(operation, javaType, "id");
}
addDefaultDomainObjectType(operation);
addNotFoundException(operation);
}
@Override
public String getGenericType(RepositoryOperation operation) {
Parameter idParam = (Parameter) operation.getParameters().get(0);
String idTypeName = idParam.getType();
// use object types
idTypeName = primitiveTypeMapper.mapPrimitiveType2ObjectTypeName(idTypeName);
return "<" + helperBase.getTypeName(operation, false) + ", " + idTypeName + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class PopulateAssociationsStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()) {
addDefaultAggregateRootParameter(operation, "entity");
addParameter(operation, propBase.getJavaType("AssociationSpecification"), "associationSpecification");
}
addDefaultDomainObjectType(operation);
addNotFoundException(operation);
}
@Override
public String getGenericType(RepositoryOperation operation) {
Parameter firstParam = (Parameter) operation.getParameters().get(0);
return "<" + helperBase.getTypeName(firstParam, false) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByKeysStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()) {
addParameter(operation, "java.util.Set<?>", "keys");
}
addDefaultDomainObjectType(operation);
if (operation.getCollectionType() == null || operation.getCollectionType().equals("")) {
operation.setCollectionType("Map");
}
if (operation.getMapKeyType() == null || operation.getMapKeyType().equals("")) {
operation.setMapKeyType("Object");
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByKeyStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()) {
DomainObject aggregateRoot = operation.getRepository().getAggregateRoot();
List<Attribute> allNaturalKeyAttributes = helper.getAllNaturalKeyAttributes(aggregateRoot);
List<Reference> allNaturalKeyReferences = helper.getAllNaturalKeyReferences(aggregateRoot);
if (allNaturalKeyAttributes.isEmpty() && allNaturalKeyReferences.isEmpty()) {
Attribute uuidAttribute = helper.getUuid(aggregateRoot);
if (uuidAttribute != null) {
addParameter(operation, helperBase.getTypeName(uuidAttribute), uuidAttribute.getName());
}
} else {
for (Attribute each : allNaturalKeyAttributes) {
addParameter(operation, helperBase.getTypeName(each), each.getName());
}
for (Reference each : allNaturalKeyReferences) {
addParameter(operation, helperBase.getTypeName(each), each.getName());
}
}
}
addDefaultDomainObjectType(operation);
addNotFoundException(operation);
}
@Override
public String getGenericType(RepositoryOperation operation) {
DomainObject aggregateRoot = operation.getRepository().getAggregateRoot();
String aggregateRootName = helperBase.getDomainPackage(aggregateRoot) + "." + aggregateRoot.getName();
return "<" + aggregateRootName + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindAllStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (propBase.getBooleanProperty("findAll.paging") && operation.getParameters().isEmpty()) {
addParameter(operation, "PagingParameter", "pagingParameter");
}
if (operation.getType() == null && operation.getDomainObjectType() == null) {
if (hasParameter(operation, "pagingParameter")) {
operation.setType("PagedResult");
addDefaultDomainObjectType(operation);
} else {
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
}
if (propBase.getBooleanProperty("generate.singleLevelFetchEager")) {
helperBase.addHint(operation, "useFetchEager");
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null || "PagedResult".equals(operation.getType())) {
return "<" + aggregateRootClassName(operation) + ">";
} else {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class CountAllStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
operation.setType("long");
}
@Override
public String getGenericType(RepositoryOperation operation) {
return "<" + aggregateRootClassName(operation) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByExampleStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
addDefaultAggregateRootParameter(operation, "example");
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
@Override
public String getGenericType(RepositoryOperation operation) {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByQueryStrategy extends AbstractGenericAccessObjectStrategy {
public FindByQueryStrategy() {
}
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()
|| (operation.getParameters().size() == 1 && hasParameter(operation, "useSingleResult"))
|| (operation.getParameters().size() == 1 && hasParameter(operation, "pagingParameter"))) {
addParameterFirst(operation, "java.util.Map<String, Object>", "parameters");
addParameterFirst(operation, "String", "query");
}
if (operation.getCollectionType() == null && (operation.getType() != null || operation.getDomainObjectType() != null)) {
helperBase.addHint(operation, "useSingleResult");
}
if (operation.getType() == null && operation.getDomainObjectType() == null) {
if (hasParameter(operation, "pagingParameter")) {
operation.setType("PagedResult");
addDefaultDomainObjectType(operation);
} else if (hasParameter(operation, "useSingleResult")
|| helperBase.hasHintImpl(operation.getHint(), "useSingleResult")) {
operation.setType("Object");
} else {
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null || "PagedResult".equals(operation.getType())) {
return "<" + aggregateRootClassName(operation) + ">";
} else {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByCriteriaStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()
|| (operation.getParameters().size() == 1 && hasParameter(operation, "pagingParameter"))) {
addParameterFirst(operation, "java.util.Map<String, Object>", "restrictions");
}
if (operation.getType() == null && operation.getDomainObjectType() == null) {
if (hasParameter(operation, "pagingParameter")) {
operation.setType("PagedResult");
addDefaultDomainObjectType(operation);
} else {
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null || "PagedResult".equals(operation.getType())) {
return "<" + aggregateRootClassName(operation) + ">";
} else {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByCriteriaQueryStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()
|| (operation.getParameters().size() == 1 && hasParameter(operation, "useSingleResult"))
|| (operation.getParameters().size() == 1 && hasParameter(operation, "pagingParameter"))) {
addParameterFirst(operation, "java.util.Map<String, Object>", "parameters");
addParameterFirst(operation, "javax.persistence.criteria.CriteriaQuery", "query");
}
if (operation.getCollectionType() == null && (operation.getType() != null || operation.getDomainObjectType() != null)) {
helperBase.addHint(operation, "useSingleResult");
}
if (operation.getType() == null && operation.getDomainObjectType() == null) {
if (hasParameter(operation, "pagingParameter")) {
operation.setType("PagedResult");
addDefaultDomainObjectType(operation);
} else if (hasParameter(operation, "useSingleResult")
|| helperBase.hasHintImpl(operation.getHint(), "useSingleResult")) {
operation.setType("Object");
} else {
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null || "PagedResult".equals(operation.getType())) {
return "<" + aggregateRootClassName(operation) + ">";
} else {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
}
@Override
public boolean isPersistentClassConstructor() {
return false;
}
}
public class FindByConditionStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (propBase.getBooleanProperty("findByCondition.paging") && operation.getParameters().isEmpty()) {
addParameter(operation, "PagingParameter", "pagingParameter");
}
if (operation.getParameters().isEmpty()
|| (operation.getParameters().size() == 1 && hasParameter(operation, "pagingParameter"))) {
String conditionalCriteriaClass;
if (propBase.hasProperty("framework.accessapi.ConditionalCriteria")) {
conditionalCriteriaClass = propBase.getProperty("framework.accessapi.ConditionalCriteria");
} else {
conditionalCriteriaClass = "org.sculptor.framework.accessapi.ConditionalCriteria";
}
addParameterFirst(operation, "java.util.List<" + conditionalCriteriaClass + ">", "condition");
}
if (operation.getType() == null && operation.getDomainObjectType() == null) {
if (hasParameter(operation, "pagingParameter")) {
operation.setType("PagedResult");
addDefaultDomainObjectType(operation);
} else {
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
}
if (propBase.getBooleanProperty("generate.singleLevelFetchEager")) {
helperBase.addHint(operation, "useFetchEager");
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null || "PagedResult".equals(operation.getType())) {
return "<" + aggregateRootClassName(operation) + ">";
} else {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class FindByConditionStatStrategy extends AbstractGenericAccessObjectStrategy {
private static final String COLUMN_STAT_REQUEST = "org.sculptor.framework.accessapi.ColumnStatRequest";
private static final String COLUMN_STAT_RESULT = "org.sculptor.framework.accessapi.ColumnStatResult";
@Override
public void addDefaultValues(RepositoryOperation operation) {
if (operation.getParameters().isEmpty()) {
String conditionalCriteriaClass;
if (propBase.hasProperty("framework.accessapi.ConditionalCriteria")) {
conditionalCriteriaClass = propBase.getProperty("framework.accessapi.ConditionalCriteria");
} else {
conditionalCriteriaClass = "org.sculptor.framework.accessapi.ConditionalCriteria";
}
addParameterFirst(operation, "java.util.List<" + conditionalCriteriaClass + ">", "condition");
String colStatParamType = "java.util.List<" + COLUMN_STAT_REQUEST + "<" + aggregateRootClassName(operation) + ">>";
addParameter(operation, colStatParamType, "columnStat");
helperBase.addHint(operation, "useSingleResult");
String colStatResultType = "java.util.List<java.util.List<" + COLUMN_STAT_RESULT + ">>";
operation.setType(colStatResultType);
}
if (operation.getType() == null && operation.getDomainObjectType() == null) {
addDefaultDomainObjectType(operation);
addDefaultCollectionType(operation);
}
}
@Override
public String getGenericType(RepositoryOperation operation) {
if (operation.getDomainObjectType() == null || "PagedResult".equals(operation.getType())) {
return "<" + aggregateRootClassName(operation) + ">";
} else {
return "<" + helperBase.getTypeName(operation, false) + ">";
}
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class MergeStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
addDefaultAggregateRootParameter(operation, "entity");
addDefaultDomainObjectType(operation);
}
@Override
public String getGenericType(RepositoryOperation operation) {
Parameter firstParam = (Parameter) operation.getParameters().get(0);
return "<" + helperBase.getTypeName(firstParam, false) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return false;
}
}
public class SaveStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
addDefaultAggregateRootParameter(operation, "entity");
addDefaultDomainObjectType(operation);
}
@Override
public String getGenericType(RepositoryOperation operation) {
Parameter firstParam = (Parameter) operation.getParameters().get(0);
return "<" + helperBase.getTypeName(firstParam, false) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
public class DeleteStrategy extends AbstractGenericAccessObjectStrategy {
@Override
public void addDefaultValues(RepositoryOperation operation) {
addDefaultAggregateRootParameter(operation, "entity");
}
@Override
public String getGenericType(RepositoryOperation operation) {
Parameter firstParam = (Parameter) operation.getParameters().get(0);
return "<" + helperBase.getTypeName(firstParam, false) + ">";
}
@Override
public boolean isPersistentClassConstructor() {
return true;
}
}
}