You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/02/01 13:23:55 UTC
[07/10] cayenne git commit: CAY-2215 split cayenne-tools into
cayenne-cgen and cayenne-ant
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java
new file mode 100644
index 0000000..a9d1dfe
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientDataMapArtifact.java
@@ -0,0 +1,50 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.util.Util;
+
+import java.util.Collection;
+
+public class ClientDataMapArtifact extends DataMapArtifact {
+
+ public ClientDataMapArtifact(DataMap dataMap, Collection<QueryDescriptor> queries) {
+ super(dataMap, queries);
+
+ }
+
+ @Override
+ public String getQualifiedBaseClassName() {
+
+ return dataMap.getDefaultClientSuperclass();
+ }
+
+ @Override
+ public String getQualifiedClassName() {
+ String clientPrefix = "";
+ if (Util.nullSafeEquals(dataMap.getDefaultClientPackage(), dataMap.getDefaultPackage())) {
+ clientPrefix = "Client_";
+ }
+
+ return dataMap.getNameWithDefaultClientPackage(Util.underscoredToJava(clientPrefix + dataMap.getName(), true));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientEntityArtifact.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientEntityArtifact.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientEntityArtifact.java
new file mode 100644
index 0000000..d20a2d4
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientEntityArtifact.java
@@ -0,0 +1,45 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.map.ObjEntity;
+
+/**
+ * Client code generation artifact based on ObjEntity.
+ *
+ * @since 3.0
+ */
+public class ClientEntityArtifact extends EntityArtifact {
+
+ public ClientEntityArtifact(ObjEntity entity) {
+ super(entity);
+ }
+
+ @Override
+ public String getQualifiedBaseClassName() {
+ return (entity.getClientSuperClassName() != null) ? entity
+ .getClientSuperClassName() : PersistentObject.class.getName();
+ }
+
+ @Override
+ public String getQualifiedClassName() {
+ return entity.getClientClassName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java
new file mode 100644
index 0000000..8e60495
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapArtifact.java
@@ -0,0 +1,137 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.util.Util;
+import org.apache.velocity.VelocityContext;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * {@link Artifact} facade for a DataMap.
+ *
+ * @since 3.0
+ */
+public class DataMapArtifact implements Artifact {
+
+ public static final String DATAMAP_UTILS_KEY = "dataMapUtils";
+
+ protected DataMap dataMap;
+ protected Collection<QueryDescriptor> selectQueries;
+ protected Collection<QueryDescriptor> sqlTemplateQueries;
+ protected Collection<QueryDescriptor> procedureQueries;
+ protected Collection<QueryDescriptor> ejbqlQueries;
+ protected Collection<String> queryNames;
+
+ public DataMapArtifact(DataMap dataMap, Collection<QueryDescriptor> queries) {
+ this.dataMap = dataMap;
+ selectQueries = new LinkedList<>();
+ sqlTemplateQueries = new LinkedList<>();
+ procedureQueries = new LinkedList<>();
+ ejbqlQueries = new LinkedList<>();
+ queryNames = new LinkedList<>();
+ addQueries(queries);
+ }
+
+ public String getQualifiedBaseClassName() {
+ return Object.class.getName();
+ }
+
+ public String getQualifiedClassName() {
+ return dataMap.getNameWithDefaultPackage(Util.underscoredToJava(dataMap.getName(), true));
+ }
+
+ public Object getObject() {
+ return this;
+ }
+
+ public void postInitContext(VelocityContext context) {
+ DataMapUtils dataMapUtils = new DataMapUtils();
+ context.put(DATAMAP_UTILS_KEY, dataMapUtils);
+ }
+
+ public TemplateType[] getTemplateTypes(ArtifactGenerationMode mode) {
+ switch (mode) {
+ case SINGLE_CLASS:
+ return new TemplateType[] {
+ TemplateType.DATAMAP_SINGLE_CLASS
+ };
+ case GENERATION_GAP:
+ return new TemplateType[] {
+ TemplateType.DATAMAP_SUPERCLASS, TemplateType.DATAMAP_SUBCLASS
+ };
+ default:
+ return new TemplateType[0];
+ }
+ }
+
+ private void addQueries(Collection<QueryDescriptor> queries) {
+ if (queries != null) {
+ for (QueryDescriptor query : queries) {
+ addQuery(query);
+ }
+ }
+ }
+
+ private void addQuery(QueryDescriptor query) {
+
+ switch (query.getType()) {
+ case QueryDescriptor.SELECT_QUERY:
+ selectQueries.add(query);
+ break;
+ case QueryDescriptor.PROCEDURE_QUERY:
+ procedureQueries.add(query);
+ break;
+ case QueryDescriptor.SQL_TEMPLATE:
+ sqlTemplateQueries.add(query);
+ break;
+ case QueryDescriptor.EJBQL_QUERY:
+ ejbqlQueries.add(query);
+ break;
+ }
+
+ if (query.getName() != null && !"".equals(query.getName())) {
+ queryNames.add(query.getName());
+ }
+ }
+
+ public Collection<QueryDescriptor> getSelectQueries() {
+ return selectQueries;
+ }
+
+ public boolean hasSelectQueries() {
+ return selectQueries.size() > 0;
+ }
+
+ public boolean hasQueryNames() {
+ return !queryNames.isEmpty();
+ }
+
+ public Collection<String> getQueryNames() {
+ return queryNames;
+ }
+
+ public DataMap getDataMap() {
+ return dataMap;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapUtils.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapUtils.java
new file mode 100644
index 0000000..a0013cc
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/DataMapUtils.java
@@ -0,0 +1,219 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+import org.apache.cayenne.exp.ExpressionParameter;
+import org.apache.cayenne.exp.parser.ASTList;
+import org.apache.cayenne.exp.parser.ASTObjPath;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.PathComponent;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.map.SelectQueryDescriptor;
+import org.apache.cayenne.query.Ordering;
+import org.apache.cayenne.util.CayenneMapEntry;
+import org.apache.cayenne.util.Util;
+import org.apache.commons.collections.set.ListOrderedSet;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Attributes and Methods for working with Queries.
+ *
+ * @since 3.0
+ */
+public class DataMapUtils {
+
+ Map<String, Map<String, String>> queriesMap = new HashMap<>();
+
+ /**
+ * Return valid method name based on query name (replace all illegal
+ * characters with underscore '_').
+ *
+ * @param query
+ * @return Method name that perform query.
+ */
+ public String getQueryMethodName(QueryDescriptor query) {
+ return Util.underscoredToJava(query.getName(), true);
+ }
+
+ /**
+ * Get all parameter names that used in query qualifier.
+ *
+ * @param query
+ * @return Parameter names.
+ */
+ public Collection getParameterNames(SelectQueryDescriptor query) {
+
+ if (query.getQualifier() == null) {
+ return Collections.EMPTY_SET;
+ }
+
+ Map<String, String> queryParameters = queriesMap.get(query.getName());
+
+ if (queryParameters == null) {
+ queryParameters = getParameterNames(query.getQualifier(), query.getRoot());
+ queriesMap.put(query.getName(), queryParameters);
+ }
+
+ return parseQualifier(query.getQualifier().toString());
+ }
+
+ public Boolean isValidParameterNames(SelectQueryDescriptor query) {
+
+ if (query.getQualifier() == null) {
+ return true;
+ }
+
+ Map<String, String> queryParameters = queriesMap.get(query.getName());
+
+ if (queryParameters == null) {
+ try {
+ queryParameters = getParameterNames(query.getQualifier(), query.getRoot());
+ } catch (Exception e) {
+ // if we have wrong path in queryParameters return false.
+ return false;
+ }
+ }
+
+ for (Ordering ordering : query.getOrderings()) {
+ // validate paths in ordering
+ String path = ordering.getSortSpecString();
+ Iterator<CayenneMapEntry> it = ((ObjEntity) query.getRoot()).resolvePathComponents(path);
+ while (it.hasNext()) {
+ try {
+ it.next();
+ } catch (ExpressionException e) {
+ // if we have wrong path in orderings return false.
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get list of parameter names in the same order as in qualifier.
+ *
+ * @param qualifierString
+ * to be parsed
+ * @return List of parameter names.
+ */
+ private Set parseQualifier(String qualifierString) {
+ Set result = new ListOrderedSet();
+ Pattern pattern = Pattern.compile("\\$[\\w]+");
+ Matcher matcher = pattern.matcher(qualifierString);
+ while (matcher.find()) {
+ String name = matcher.group();
+ result.add(Util.underscoredToJava(name.substring(1), false));
+ }
+
+ return result;
+ }
+
+ public boolean hasParameters(SelectQueryDescriptor query) {
+ Map queryParameters = queriesMap.get(query.getName());
+
+ if (queryParameters == null) {
+ return false;
+ }
+
+ return queryParameters.keySet().size() > 0;
+
+ }
+
+ /**
+ * Get type of parameter for given name.
+ *
+ * @param query
+ * @param name
+ * @return Parameter type.
+ */
+ public String getParameterType(SelectQueryDescriptor query, String name) {
+ return queriesMap.get(query.getName()).get(name);
+ }
+
+ private Map<String, String> getParameterNames(Expression expression, Object root) {
+ if (expression != null) {
+ Map<String, String> types = new HashMap<>();
+ String typeName = "";
+ List<String> names = new LinkedList<String>();
+
+ for (int i = 0; i < expression.getOperandCount(); i++) {
+ Object operand = expression.getOperand(i);
+
+ if (operand instanceof Expression) {
+ types.putAll(getParameterNames((Expression) operand, root));
+ }
+
+ if (operand instanceof ASTObjPath) {
+ PathComponent<ObjAttribute, ObjRelationship> component = ((Entity) root).lastPathComponent(
+ (ASTObjPath) operand, null);
+ ObjAttribute attribute = component.getAttribute();
+ if (attribute != null) {
+ typeName = attribute.getType();
+ } else {
+ ObjRelationship relationship = component.getRelationship();
+ if (relationship != null) {
+ typeName = ((ObjEntity) relationship.getTargetEntity()).getClassName();
+ } else {
+ typeName = "Object";
+ }
+ }
+ }
+
+ if (operand instanceof ASTList) {
+ Object[] values = (Object[]) ((ASTList) operand).getOperand(0);
+ for (Object value : values) {
+ if (value instanceof ExpressionParameter) {
+ names.add(((ExpressionParameter) value).getName());
+ }
+ }
+ }
+
+ if (operand instanceof ExpressionParameter) {
+ names.add(((ExpressionParameter) operand).getName());
+ }
+
+ }
+
+ for (String name : names) {
+ types.put(Util.underscoredToJava(name, false), typeName);
+ }
+
+ return types;
+ }
+ return Collections.EMPTY_MAP;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EmbeddableArtifact.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EmbeddableArtifact.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EmbeddableArtifact.java
new file mode 100644
index 0000000..8e6ea43
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EmbeddableArtifact.java
@@ -0,0 +1,68 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.map.Embeddable;
+import org.apache.velocity.VelocityContext;
+
+/**
+ * {@link Artifact} facade for an {@link Embeddable}.
+ *
+ * @since 3.0
+ */
+public class EmbeddableArtifact implements Artifact {
+
+ protected Embeddable embeddable;
+
+ public EmbeddableArtifact(Embeddable embeddable) {
+ this.embeddable = embeddable;
+ }
+
+ public Object getObject() {
+ return embeddable;
+ }
+
+ public String getQualifiedBaseClassName() {
+ return Object.class.getName();
+ }
+
+ public String getQualifiedClassName() {
+ return embeddable.getClassName();
+ }
+
+ public TemplateType[] getTemplateTypes(ArtifactGenerationMode mode) {
+ switch (mode) {
+ case SINGLE_CLASS:
+ return new TemplateType[] {
+ TemplateType.EMBEDDABLE_SINGLE_CLASS
+ };
+ case GENERATION_GAP:
+ return new TemplateType[] {
+ TemplateType.EMBEDDABLE_SUPERCLASS,
+ TemplateType.EMBEDDABLE_SUBCLASS
+ };
+ default:
+ return new TemplateType[0];
+ }
+ }
+
+ public void postInitContext(VelocityContext context) {
+ // noop - no special keys...
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityArtifact.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityArtifact.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityArtifact.java
new file mode 100644
index 0000000..394304f
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityArtifact.java
@@ -0,0 +1,98 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.velocity.VelocityContext;
+
+/**
+ * {@link Artifact} facade for an ObjEntity.
+ *
+ * @since 3.0
+ */
+public class EntityArtifact implements Artifact {
+
+ public static String ENTITY_UTILS_KEY = "entityUtils";
+
+ protected ObjEntity entity;
+
+ public EntityArtifact(ObjEntity entity) {
+ this.entity = entity;
+ }
+
+ /**
+ * Returns ObjEntity.
+ */
+ public Object getObject() {
+ return entity;
+ }
+
+ public String getQualifiedBaseClassName() {
+ return (entity.getSuperClassName() != null)
+ ? entity.getSuperClassName()
+ : CayenneDataObject.class.getName();
+ }
+
+ public String getQualifiedClassName() {
+ return entity.getClassName();
+ }
+
+ public TemplateType getSingleClassType() {
+ return TemplateType.ENTITY_SINGLE_CLASS;
+ }
+
+ public TemplateType getSubclassType() {
+ return TemplateType.ENTITY_SUBCLASS;
+ }
+
+ public TemplateType getSuperClassType() {
+ return TemplateType.ENTITY_SUPERCLASS;
+ }
+
+ public TemplateType[] getTemplateTypes(ArtifactGenerationMode mode) {
+ switch (mode) {
+ case SINGLE_CLASS:
+ return new TemplateType[] {
+ TemplateType.ENTITY_SINGLE_CLASS
+ };
+ case GENERATION_GAP:
+ return new TemplateType[] {
+ TemplateType.ENTITY_SUPERCLASS, TemplateType.ENTITY_SUBCLASS
+ };
+ default:
+ return new TemplateType[0];
+ }
+ }
+
+ public void postInitContext(VelocityContext context) {
+ EntityUtils metadata = new EntityUtils(
+ entity.getDataMap(),
+ entity,
+ (String) context.get(BASE_CLASS_KEY),
+ (String) context.get(BASE_PACKAGE_KEY),
+ (String) context.get(SUPER_CLASS_KEY),
+ (String) context.get(SUPER_PACKAGE_KEY),
+ (String) context.get(SUB_CLASS_KEY),
+ (String) context.get(SUB_PACKAGE_KEY));
+
+ context.put(ENTITY_UTILS_KEY, metadata);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityUtils.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityUtils.java
new file mode 100644
index 0000000..ecf2a3f
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/EntityUtils.java
@@ -0,0 +1,274 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import java.util.Collection;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.MappingNamespace;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.Relationship;
+
+/**
+ * Attributes and Methods for working with ObjEntities.
+ *
+ * @since 1.2
+ */
+public class EntityUtils {
+
+ // template substitution values
+ protected String subClassName;
+ protected String superClassName;
+ protected String baseClassName;
+ protected String subPackageName;
+ protected String superPackageName;
+ protected String basePackageName;
+
+ protected DataMap primaryDataMap;
+ protected ObjEntity objEntity;
+
+ protected Collection<String> callbackNames;
+
+ public EntityUtils(DataMap dataMap, ObjEntity objEntity, String fqnBaseClass, String fqnSuperClass,
+ String fqnSubClass) {
+
+ StringUtils stringUtils = StringUtils.getInstance();
+
+ this.baseClassName = stringUtils.stripPackageName(fqnBaseClass);
+ this.basePackageName = stringUtils.stripClass(fqnBaseClass);
+ this.superClassName = stringUtils.stripPackageName(fqnSuperClass);
+ this.superPackageName = stringUtils.stripClass(fqnSuperClass);
+ this.subClassName = stringUtils.stripPackageName(fqnSubClass);
+ this.subPackageName = stringUtils.stripClass(fqnSubClass);
+
+ this.primaryDataMap = dataMap;
+
+ this.objEntity = objEntity;
+ this.callbackNames = objEntity.getCallbackMethods();
+ }
+
+ EntityUtils(DataMap dataMap, ObjEntity objEntity, String baseClassName, String basePackageName,
+ String superClassName, String superPackageName, String subClassName, String subPackageName) {
+
+ this.baseClassName = baseClassName;
+ this.basePackageName = basePackageName;
+ this.superClassName = superClassName;
+ this.superPackageName = superPackageName;
+ this.subClassName = subClassName;
+ this.subPackageName = subPackageName;
+
+ this.primaryDataMap = dataMap;
+
+ this.objEntity = objEntity;
+ this.callbackNames = objEntity.getCallbackMethods();
+ }
+
+ /**
+ * @return Returns the primary DataMap.
+ * @since 1.2
+ */
+ public DataMap getPrimaryDataMap() {
+ return primaryDataMap;
+ }
+
+ /**
+ * Returns the EntityResolver for this set of DataMaps.
+ *
+ * @since 1.2
+ */
+ public MappingNamespace getEntityResolver() {
+ return primaryDataMap.getNamespace();
+ }
+
+ /**
+ * Returns true if current ObjEntity is defined as abstract.
+ */
+ public boolean isAbstract() {
+ return isAbstract(objEntity);
+ }
+
+ /**
+ * Returns true if current ObjEntity is defined as abstract.
+ */
+ public boolean isAbstract(ObjEntity anObjEntity) {
+ return anObjEntity != null && anObjEntity.isAbstract();
+ }
+
+ /**
+ * Returns true if current ObjEntity contains at least one toMany
+ * relationship.
+ */
+ public boolean hasToManyRelationships() {
+ return hasToManyRelationships(objEntity);
+ }
+
+ /**
+ * Returns true if an ObjEntity contains at least one toMany relationship.
+ */
+ public boolean hasToManyRelationships(ObjEntity anObjEntity) {
+ if (anObjEntity == null) {
+ return false;
+ }
+
+ for (Relationship r : anObjEntity.getRelationships()) {
+ if (r.isToMany()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if current ObjEntity contains at least one toMany
+ * relationship, ignoring those declared in superentities.
+ *
+ * @since 1.2
+ */
+ public boolean hasToManyDeclaredRelationships() {
+ return hasToManyDeclaredRelationships(objEntity);
+ }
+
+ /**
+ * Returns true if an ObjEntity contains at least one toMany relationship,
+ * ignoring those declared in superentities.
+ *
+ * @since 1.2
+ */
+ public boolean hasToManyDeclaredRelationships(ObjEntity anObjEntity) {
+ if (anObjEntity == null) {
+ return false;
+ }
+
+ for (Relationship r : anObjEntity.getDeclaredRelationships()) {
+ if (r.isToMany()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if current ObjEntity contains at least one toOne
+ * relationship.
+ */
+ public boolean hasToOneRelationships() {
+ return hasToOneRelationships(objEntity);
+ }
+
+ /**
+ * Returns true if an ObjEntity contains at least one toOne relationship.
+ */
+ public boolean hasToOneRelationships(ObjEntity anObjEntity) {
+ if (anObjEntity == null) {
+ return false;
+ }
+
+ for (Relationship r : anObjEntity.getRelationships()) {
+ if (!r.isToMany()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if current ObjEntity contains at least one toOne
+ * relationship, ignoring those declared in superentities.
+ */
+ public boolean hasToOneDeclaredRelationships() {
+ return hasToOneDeclaredRelationships(objEntity);
+ }
+
+ /**
+ * Returns true if an ObjEntity contains at least one toOne relationship,
+ * ignoring those declared in superentities.
+ */
+ public boolean hasToOneDeclaredRelationships(ObjEntity anObjEntity) {
+ if (anObjEntity == null) {
+ return false;
+ }
+
+ for (Relationship r : anObjEntity.getDeclaredRelationships()) {
+ if (!r.isToMany()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the map key type for a collection relationship of type
+ * java.util.Map.
+ *
+ * @param relationship
+ * The relationship to look up type information for.
+ * @return The type of the attribute keyed on.
+ */
+ public String getMapKeyType(final ObjRelationship relationship) {
+
+ ObjEntity targetEntity = (ObjEntity) relationship.getTargetEntity();
+
+ // If the map key is null, then we're doing look-ups by actual object
+ // key.
+ if (relationship.getMapKey() == null) {
+
+ // If it's a multi-column key, then the return type is always
+ // ObjectId.
+ DbEntity dbEntity = targetEntity.getDbEntity();
+ if ((dbEntity != null) && (dbEntity.getPrimaryKeys().size() > 1)) {
+ return ObjectId.class.getName();
+ }
+
+ // If it's a single column key or no key exists at all, then we
+ // really don't
+ // know what the key type is,
+ // so default to Object.
+ return Object.class.getName();
+ }
+
+ // If the map key is a non-default attribute, then fetch the attribute
+ // and return
+ // its type.
+ ObjAttribute attribute = targetEntity.getAttribute(relationship.getMapKey());
+ if (attribute == null) {
+ throw new CayenneRuntimeException("Invalid map key '" + relationship.getMapKey()
+ + "', no matching attribute found");
+ }
+
+ return attribute.getType();
+ }
+
+ /**
+ * @return the list of all callback names registered for the entity.
+ * @since 3.0
+ */
+ public Collection<String> getCallbackNames() {
+ return callbackNames;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ImportUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ImportUtils.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ImportUtils.java
new file mode 100644
index 0000000..af40499
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ImportUtils.java
@@ -0,0 +1,266 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.util.Util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Methods for mangling strings.
+ *
+ */
+public class ImportUtils {
+
+ public static final String importOrdering[] = new String[] { "java.", "javax.", "org.", "com." };
+
+ static final String primitives[] = new String[] { "long", "double", "byte", "boolean", "float", "short", "int",
+ "char" };
+
+ static final String primitiveClasses[] = new String[] { Long.class.getName(), Double.class.getName(),
+ Byte.class.getName(), Boolean.class.getName(), Float.class.getName(), Short.class.getName(),
+ Integer.class.getName(), Character.class.getName() };
+
+ static Map<String, String> classesForPrimitives = Util.toMap(primitives, primitiveClasses);
+ static Map<String, String> primitivesForClasses = Util.toMap(primitiveClasses, primitives);
+
+ protected Map<String, String> importTypesMap = new HashMap<>();
+
+ // Types forced to be FQN
+ protected Map<String, String> reservedImportTypesMap = new HashMap<>();
+
+ protected String packageName;
+
+ public ImportUtils() {
+ super();
+ }
+
+ protected boolean canRegisterType(String typeName) {
+ // Not sure why this would ever happen, but it did
+ if (null == typeName)
+ return false;
+
+ StringUtils stringUtils = StringUtils.getInstance();
+ String typeClassName = stringUtils.stripPackageName(typeName);
+ String typePackageName = stringUtils.stripClass(typeName);
+
+ if (typePackageName.length() == 0)
+ return false; // disallow non-packaged types (primitives, probably)
+ if ("java.lang".equals(typePackageName))
+ return false;
+
+ // Can only have one type -- rest must use fqn
+ if (reservedImportTypesMap.containsKey(typeClassName))
+ return false;
+ if (importTypesMap.containsKey(typeClassName))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Reserve a fully-qualified data type class name so it cannot be used by
+ * another class. No import statements will be generated for reserved types.
+ * Typically, this is the fully-qualified class name of the class being
+ * generated.
+ *
+ * @param typeName
+ * FQ data type class name.
+ */
+ public void addReservedType(String typeName) {
+ if (!canRegisterType(typeName))
+ return;
+
+ StringUtils stringUtils = StringUtils.getInstance();
+ String typeClassName = stringUtils.stripPackageName(typeName);
+
+ reservedImportTypesMap.put(typeClassName, typeName);
+ }
+
+ /**
+ * Register a fully-qualified data type class name. For example,
+ * org.apache.cayenne.CayenneDataObject.
+ *
+ * @param typeName
+ * FQ data type class name.
+ */
+ public void addType(String typeName) {
+ if (!canRegisterType(typeName))
+ return;
+
+ StringUtils stringUtils = StringUtils.getInstance();
+ String typePackageName = stringUtils.stripClass(typeName);
+ String typeClassName = stringUtils.stripPackageName(typeName);
+
+ if (typePackageName.equals(packageName))
+ return;
+
+ importTypesMap.put(typeClassName, typeName);
+ }
+
+ /**
+ * Add the package name to use for this importUtil invocation.
+ *
+ * @param packageName
+ */
+ public void setPackage(String packageName) {
+ this.packageName = packageName;
+ }
+
+ /**
+ * Performs processing similar to <code>formatJavaType(String)</code>, with
+ * special handling of primitive types and their Java class counterparts.
+ * This method allows users to make a decision whether to use primitives or
+ * not, regardless of how type is mapped.
+ */
+ public String formatJavaType(String typeName, boolean usePrimitives) {
+ if (usePrimitives) {
+ String primitive = primitivesForClasses.get(typeName);
+ return (primitive != null) ? primitive : formatJavaType(typeName);
+ } else {
+ String primitiveClass = classesForPrimitives.get(typeName);
+ return (primitiveClass != null) ? formatJavaType(primitiveClass) : formatJavaType(typeName);
+ }
+ }
+
+ /**
+ * Removes registered package and non-reserved registered type name prefixes
+ * from java types
+ */
+ public String formatJavaType(String typeName) {
+ if (typeName != null) {
+ StringUtils stringUtils = StringUtils.getInstance();
+ String typeClassName = stringUtils.stripPackageName(typeName);
+
+ if (!reservedImportTypesMap.containsKey(typeClassName)) {
+ if (importTypesMap.containsKey(typeClassName)) {
+ if (typeName.equals(importTypesMap.get(typeClassName)))
+ return typeClassName;
+ }
+ }
+
+ String typePackageName = stringUtils.stripClass(typeName);
+ if ("java.lang".equals(typePackageName))
+ return typeClassName;
+ if ((null != packageName) && (packageName.equals(typePackageName)))
+ return typeClassName;
+ }
+
+ return typeName;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public String formatJavaTypeAsNonBooleanPrimitive(String type) {
+ String value = ImportUtils.classesForPrimitives.get(type);
+ return formatJavaType(value != null ? value : type);
+ }
+
+ /**
+ * @since 3.0
+ */
+ public boolean isNonBooleanPrimitive(String type) {
+ return ImportUtils.classesForPrimitives.containsKey(type) && !isBoolean(type);
+ }
+
+ /**
+ * @since 3.0
+ */
+ public boolean isBoolean(String type) {
+ return "boolean".equals(type);
+ }
+
+ /**
+ * Generate package and list of import statements based on the registered
+ * types.
+ */
+ public String generate() {
+ StringBuilder outputBuffer = new StringBuilder();
+
+ if (null != packageName) {
+ outputBuffer.append("package ");
+ outputBuffer.append(packageName);
+
+ // Using UNIX line endings intentionally - generated Java files
+ // should look
+ // the same regardless of platform to prevent developer teams
+ // working on
+ // multiple OS's to override each other's work
+ outputBuffer.append(";\n\n");
+ }
+
+ List<String> typesList = new ArrayList<>(importTypesMap.values());
+ Collections.sort(typesList, new Comparator<String>() {
+
+ public int compare(String s1, String s2) {
+
+ for (String ordering : importOrdering) {
+ if ((s1.startsWith(ordering)) && (!s2.startsWith(ordering))) {
+ return -1;
+ }
+ if ((!s1.startsWith(ordering)) && (s2.startsWith(ordering))) {
+ return 1;
+ }
+ }
+
+ return s1.compareTo(s2);
+ }
+ });
+
+ String lastStringPrefix = null;
+ boolean firstIteration = true;
+ for (String typeName : typesList) {
+
+ if (firstIteration) {
+ firstIteration = false;
+ } else {
+ outputBuffer.append('\n');
+ }
+ // Output another newline if we're in a different root package.
+ // Find root package
+ String thisStringPrefix = typeName;
+ int dotIndex = typeName.indexOf('.');
+ if (-1 != dotIndex) {
+ thisStringPrefix = typeName.substring(0, dotIndex);
+ }
+ // if this isn't the first import,
+ if (null != lastStringPrefix) {
+ // and it's different from the last import
+ if (false == thisStringPrefix.equals(lastStringPrefix)) {
+ // output a newline; force UNIX style per comment above
+ outputBuffer.append("\n");
+ }
+ }
+ lastStringPrefix = thisStringPrefix;
+
+ outputBuffer.append("import ");
+ outputBuffer.append(typeName);
+ outputBuffer.append(';');
+ }
+
+ return outputBuffer.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/StringUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/StringUtils.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/StringUtils.java
new file mode 100644
index 0000000..778a09b
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/StringUtils.java
@@ -0,0 +1,213 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+import org.apache.cayenne.project.validation.NameValidationHelper;
+import org.apache.cayenne.util.Util;
+
+/**
+ * Methods for mangling strings.
+ */
+public class StringUtils {
+
+ private static StringUtils sharedInstance;
+
+ public static StringUtils getInstance() {
+ if (null == sharedInstance) {
+ sharedInstance = new StringUtils();
+ }
+
+ return sharedInstance;
+ }
+
+ /**
+ * Prepends underscore to variable name if necessary to remove conflict with reserved
+ * keywords.
+ */
+ public String formatVariableName(String variableName) {
+ if (NameValidationHelper.getInstance().isReservedJavaKeyword(variableName)) {
+ return "_" + variableName;
+ }
+ else {
+ return variableName;
+ }
+ }
+
+ /**
+ * Removes package name, leaving base name.
+ *
+ * @since 1.2
+ */
+ public String stripPackageName(String fullyQualifiedClassName) {
+ return Util.stripPackageName(fullyQualifiedClassName);
+ }
+
+ /**
+ * Removes base name, leaving package name.
+ *
+ * @since 1.2
+ */
+ public String stripClass(String aString) {
+ if (aString == null || aString.length() == 0)
+ return aString;
+
+ int lastDot = aString.lastIndexOf('.');
+
+ if (-1 == lastDot)
+ return "";
+
+ return aString.substring(0, lastDot);
+ }
+
+ /**
+ * Capitalizes the first letter of the property name.
+ *
+ * @since 1.1
+ */
+ public String capitalized(String name) {
+ if (name == null || name.length() == 0)
+ return name;
+
+ char c = Character.toUpperCase(name.charAt(0));
+ return (name.length() == 1) ? Character.toString(c) : c + name.substring(1);
+ }
+
+ /**
+ * Returns string with lowercased first letter
+ *
+ * @since 1.2
+ */
+ public static String uncapitalized(String aString) {
+ if (aString == null || aString.length() == 0)
+ return aString;
+
+ char c = Character.toLowerCase(aString.charAt(0));
+ return (aString.length() == 1) ? Character.toString(c) : c + aString.substring(1);
+ }
+
+ /**
+ * Converts property name to Java constants naming convention.
+ *
+ * @since 1.1
+ */
+ public String capitalizedAsConstant(String name) {
+ if (name == null || name.length() == 0)
+ return name;
+
+ // clear of non-java chars. While the method name implies that a passed identifier
+ // is pure Java, it is used to build pk columns names and such, so extra safety
+ // check is a good idea
+ name = Util.specialCharsToJava(name);
+
+ char charArray[] = name.toCharArray();
+ StringBuilder buffer = new StringBuilder();
+
+ for (int i = 0; i < charArray.length; i++) {
+ if ((Character.isUpperCase(charArray[i])) && (i != 0)) {
+
+ char prevChar = charArray[i - 1];
+ if ((Character.isLowerCase(prevChar))) {
+ buffer.append("_");
+ }
+ }
+
+ buffer.append(Character.toUpperCase(charArray[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Converts entity or property name to a plural form. For example:
+ * <ul>
+ * <li>pluralize("Word") == "Words"</li>
+ * <li>pluralize("Status") == "Statuses"</li>
+ * <li>pluralize("Index") == "Indexes"</li>
+ * <li>pluralize("Factory") == "Factories"</li>
+ * </ul>
+ * <p>
+ * As of 3.1 this method is not used in bundled templates, and is present here for
+ * user templates convenience.
+ *
+ * @since 3.1
+ */
+ public String pluralize(String str) {
+ if (str == null || str.length() == 0) {
+ return str;
+ }
+ else if (str.endsWith("s") || str.endsWith("x")) {
+ return str + "es";
+ }
+ else if (str.endsWith("y")) {
+ return str.substring(0, str.length() - 1) + "ies";
+ }
+ else {
+ return str + "s";
+ }
+ }
+
+ /**
+ * <p>
+ * Strip generic definition from string
+ * </p>
+ * <p>For example: List>Integer< == List</p>
+ * @since 4.0
+ */
+ public String stripGeneric(String str) {
+ if(str == null) {
+ return null;
+ }
+ int start = str.indexOf('<');
+ if(start == -1) {
+ return str;
+ }
+ int end = str.lastIndexOf('>');
+ if(end == -1) {
+ return str;
+ } else if(end == str.length() - 1) {
+ return str.substring(0, start);
+ }
+ return str.substring(0, start) + str.substring(end+1);
+ }
+
+ public String replaceWildcardInStringWithString(String wildcard, String pattern, String replacement) {
+ if (pattern == null || wildcard == null) {
+ return pattern;
+ }
+
+ StringBuilder buffer = new StringBuilder();
+ int lastPos = 0;
+ int wildCardPos = pattern.indexOf(wildcard);
+ while (wildCardPos != -1) {
+ if (lastPos != wildCardPos) {
+ buffer.append(pattern.substring(lastPos, wildCardPos));
+ }
+ buffer.append(replacement);
+ lastPos += wildCardPos + wildcard.length();
+ wildCardPos = pattern.indexOf(wildcard, lastPos);
+ }
+
+ if (lastPos < pattern.length()) {
+ buffer.append(pattern.substring(lastPos));
+ }
+
+ return buffer.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/TemplateType.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/TemplateType.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/TemplateType.java
new file mode 100644
index 0000000..109627e
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/TemplateType.java
@@ -0,0 +1,55 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.gen;
+
+/**
+ * Defines class generation template types.
+ *
+ * @since 3.0
+ */
+public enum TemplateType {
+
+ ENTITY_SINGLE_CLASS(false),
+
+ ENTITY_SUPERCLASS(true),
+
+ ENTITY_SUBCLASS(false),
+
+ EMBEDDABLE_SINGLE_CLASS(false),
+
+ EMBEDDABLE_SUPERCLASS(true),
+
+ EMBEDDABLE_SUBCLASS(false),
+
+ DATAMAP_SINGLE_CLASS(false),
+
+ DATAMAP_SUPERCLASS(true),
+
+ DATAMAP_SUBCLASS(false);
+
+ private boolean superclass;
+
+ private TemplateType(boolean superclass) {
+ this.superclass = superclass;
+ }
+
+ public boolean isSuperclass() {
+ return superclass;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/package.html
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/package.html b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/package.html
new file mode 100644
index 0000000..69b8b7d
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/package.html
@@ -0,0 +1,28 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<html>
+<body>
+Contains classes that provide Java source generation facility.
+Source creation is based on a set of templates parsed
+during generation process, using Jakarta Velocity template engine.
+
+<p><i>For more information see <a href="../../../../../../index.html"
+target="_top">Cayenne User Guide.</a></i></p>
+</body>
+</html>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
new file mode 100644
index 0000000..4d068d8
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
@@ -0,0 +1,85 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.tools;
+
+import org.apache.cayenne.dbsync.filter.NameFilter;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.map.ObjEntity;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Performs entity filtering to build a collection of entities that should be used in
+ * class generation.
+ *
+ * @since 3.0
+ */
+class CayenneGeneratorEntityFilterAction {
+
+ private NameFilter nameFilter;
+ private boolean client;
+
+ Collection<Embeddable> getFilteredEmbeddables(DataMap mainDataMap) {
+ Collection<Embeddable> embeddables = new ArrayList<>(mainDataMap.getEmbeddables());
+
+ // filter out excluded entities...
+ Iterator<Embeddable> it = embeddables.iterator();
+
+ while (it.hasNext()) {
+ Embeddable e = it.next();
+
+ // note that unlike entity, embeddable is matched by class name as it doesn't
+ // have a symbolic name...
+ if (!nameFilter.isIncluded(e.getClassName())) {
+ it.remove();
+ }
+ }
+
+ return embeddables;
+ }
+
+ Collection<ObjEntity> getFilteredEntities(DataMap mainDataMap)
+ throws MalformedURLException {
+
+ Collection<ObjEntity> entities = new ArrayList<>(mainDataMap.getObjEntities());
+
+ // filter out excluded entities...
+ Iterator<ObjEntity> it = entities.iterator();
+ while (it.hasNext()) {
+ ObjEntity e = it.next();
+ if (e.isGeneric() || client && !e.isClientAllowed() || !nameFilter.isIncluded(e.getName())) {
+ it.remove();
+ }
+ }
+
+ return entities;
+ }
+
+ void setClient(boolean client) {
+ this.client = client;
+ }
+
+ public void setNameFilter(NameFilter nameFilter) {
+ this.nameFilter = nameFilter;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorMapLoaderAction.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorMapLoaderAction.java b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorMapLoaderAction.java
new file mode 100644
index 0000000..1a0a098
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorMapLoaderAction.java
@@ -0,0 +1,78 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cayenne.tools;
+
+import java.io.File;
+import java.net.MalformedURLException;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.MapLoader;
+import org.xml.sax.InputSource;
+
+/**
+ * Loads a DataMap and a shared entity namespace.
+ *
+ * @since 3.0
+ */
+class CayenneGeneratorMapLoaderAction {
+
+ private File mainDataMapFile;
+ private File[] additionalDataMapFiles;
+ private DataMap mainDataMap;
+
+ DataMap getMainDataMap() throws MalformedURLException {
+ if (mainDataMap == null) {
+ MapLoader mapLoader = new MapLoader();
+
+ DataMap mainDataMap = loadDataMap(mapLoader, mainDataMapFile);
+
+ if (additionalDataMapFiles != null) {
+
+ EntityResolver entityResolver = new EntityResolver();
+ entityResolver.addDataMap(mainDataMap);
+ mainDataMap.setNamespace(entityResolver);
+
+ for (File additionalDataMapFile : additionalDataMapFiles) {
+
+ DataMap dataMap = loadDataMap(mapLoader, additionalDataMapFile);
+ entityResolver.addDataMap(dataMap);
+ dataMap.setNamespace(entityResolver);
+ }
+ }
+
+ this.mainDataMap = mainDataMap;
+ }
+
+ return mainDataMap;
+ }
+
+ protected DataMap loadDataMap(MapLoader mapLoader, File dataMapFile) throws MalformedURLException {
+ InputSource in = new InputSource(dataMapFile.toURI().toURL().toString());
+ return mapLoader.loadDataMap(in);
+ }
+
+ void setMainDataMapFile(File mainDataMapFile) {
+ this.mainDataMapFile = mainDataMapFile;
+ }
+
+ void setAdditionalDataMapFiles(File[] additionalDataMapFiles) {
+ this.additionalDataMapFiles = additionalDataMapFiles;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-singleclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-singleclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-singleclass.vm
new file mode 100644
index 0000000..d0c7f6c
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-singleclass.vm
@@ -0,0 +1,96 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you 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.
+##
+##Terminology:
+## Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+## Super class - superclass of entity, ie, org.apache.cayenne.art.auto._Artist
+## Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+## Classes available in template
+## object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+## stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+## dataMapUtils - class for query "helper" functions: See org.apache.cayenne.gen.DataMapUtils
+## importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+## superClassName
+## superPackageName
+## subClassName
+## subPackageName
+## baseClassName
+## basePackageName
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+${importUtils.addType('java.util.List')}
+${importUtils.addType('java.util.Map')}
+${importUtils.addType('java.util.HashMap')}
+${importUtils.addType('org.apache.cayenne.ObjectContext')}
+#foreach( $selectQuery in ${object.SelectQueries})
+${importUtils.addType(${selectQuery.Root.ClassName})}
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+${importUtils.addType(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})}
+#end
+#end
+${importUtils.generate()}
+
+/**
+ * This class was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public class ${subClassName} {
+#if( ${object.hasQueryNames()})
+#foreach( $qname in ${object.QueryNames})
+
+ public static final String ${stringUtils.capitalizedAsConstant($qname)}_QUERYNAME = "$qname";
+#end
+#end
+
+private static ${subClassName} instance;
+
+ private ${subClassName}() {}
+
+ public ${subClassName} getInstance() {
+ if( instance == null) {
+ instance = new ${subClassName}();
+ }
+ return instance;
+ }
+
+#foreach( $selectQuery in ${object.SelectQueries})
+ public List<${stringUtils.stripPackageName($selectQuery.Root.ClassName)}> perform${dataMapUtils.getQueryMethodName(${selectQuery})}(ObjectContext context #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})}), ${stringUtils.stripPackageName(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})} ${parameter} #end) {
+ #if(${dataMapUtils.hasParameters($selectQuery)})
+ String[] parameters = new String[] {
+ #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+ "${parameter}",
+ #end
+ };
+
+ Object[] values = new Object[] {
+ #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+ ${parameter},
+ #end
+ };
+ #end
+
+ NamedQuery query = new NamedQuery("${selectQuery.Name}"#if(${dataMapUtils.hasParameters($selectQuery)}), parameters, values#end);
+ return context.performQuery(query);
+ }
+#end
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-subclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-subclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-subclass.vm
new file mode 100644
index 0000000..f5e0474
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-subclass.vm
@@ -0,0 +1,47 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you 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.
+##
+##Terminology:
+## Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+## Super class - superclass of entity, ie, org.apache.cayenne.art.auto._Artist
+## Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+## Classes available in template
+## stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+## dataMapUtils - class for query "helper" functions: See org.apache.cayenne.gen.dataMapUtils
+## importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${superPackageName}.${superClassName}")}##
+${importUtils.generate()}
+
+public class ${subClassName} extends ${superClassName} {
+
+ private static ${subClassName} instance;
+
+ private ${subClassName}() {}
+
+ public static ${subClassName} getInstance() {
+ if(instance == null) {
+ instance = new ${subClassName}();
+ }
+
+ return instance;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-superclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-superclass.vm
new file mode 100644
index 0000000..c196301
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/client-datamap-superclass.vm
@@ -0,0 +1,83 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you 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.
+##
+##Terminology:
+## Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+## Super class - superclass of entity, ie, org.apache.cayenne.art.auto._Artist
+## Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+## Classes available in template
+## stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+## dataMapUtils - class for query "helper" functions: See org.apache.cayenne.gen.DataMapUtils
+## importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+## superClassName
+## superPackageName
+## subClassName
+## subPackageName
+## baseClassName
+## basePackageName
+##
+${importUtils.setPackage($superPackageName)}##
+#if(${superPackageName})${importUtils.addReservedType("${superPackageName}.${superClassName}")}#end##
+#if(${basePackageName})${importUtils.addType("${basePackageName}.${baseClassName}")}#end##
+#if( ${object.hasSelectQueries()} )
+${importUtils.addType('java.util.List')}##
+${importUtils.addType('org.apache.cayenne.ObjectContext')}##
+${importUtils.addType('org.apache.cayenne.query.NamedQuery')}##
+#foreach( $selectQuery in ${object.SelectQueries})
+${importUtils.addType(${selectQuery.Root.ClientClassName})}##
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+${importUtils.addType(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})}##
+#end
+#end
+#end
+${importUtils.generate()}
+
+/**
+ * This class was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public class ${superClassName} {
+#if( ${object.hasQueryNames()})
+#foreach( $qname in ${object.QueryNames})
+
+ public static final String ${stringUtils.capitalizedAsConstant($qname)}_QUERYNAME = "$qname";
+#end
+#end
+#foreach( $selectQuery in ${object.SelectQueries})
+
+ public List<${stringUtils.stripPackageName($selectQuery.Root.ClientClassName)}> perform${dataMapUtils.getQueryMethodName(${selectQuery})}(ObjectContext context #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})}), ${stringUtils.stripPackageName(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})} ${parameter}#end) {
+#if(${dataMapUtils.hasParameters($selectQuery)})
+ String[] parameters = {
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+ "${parameter}",
+#end
+ };
+
+ Object[] values = {
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+ ${parameter},
+#end
+ };
+
+#end
+ return context.performQuery(new NamedQuery("${selectQuery.Name}"#if(${dataMapUtils.hasParameters($selectQuery)}), parameters, values#end));
+ }
+#end
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/client-subclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/client-subclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/client-subclass.vm
new file mode 100644
index 0000000..d28de85
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/client-subclass.vm
@@ -0,0 +1,57 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you 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.
+##
+## A default Cayenne template for a client-side subclass in a generated subclass/superclass pair.
+##
+## Terminology:
+## Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+## Super class - superclass of entity, ie, org.apache.cayenne.art.auto._Artist
+## Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+## Classes available in template
+## object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+## stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+## entityUtils - class for entity "helper" functions: See org.apache.cayenne.gen.EntityUtils
+## importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+## superClassName
+## superPackageName
+## subClassName
+## subPackageName
+## baseClassName
+## basePackageName
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${$subPackageName}.${subClassName}")}##
+${importUtils.addType("${superPackageName}.${superClassName}")}##
+${importUtils.generate()}
+
+/**
+ * A persistent class mapped as "${object.name}" Cayenne entity.
+ */
+public#if("true" == "${object.getIsAbstract()}") abstract#end class ${subClassName} extends ${superClassName} {
+
+ private static final long serialVersionUID = 1L;
+
+##callback methods
+#foreach( $cbname in ${entityUtils.callbackNames})
+ @Override
+ protected void ${cbname}() {
+ //TODO: Implement ${cbname}
+ }
+
+#end
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/client-superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/client-superclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/client-superclass.vm
new file mode 100644
index 0000000..f8c9cbe
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/client-superclass.vm
@@ -0,0 +1,248 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you 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.
+##
+##Terminology:
+## Base class - super superclass of entity, ie, org.apache.cayenne.PersistentObject or MyBaseClass
+## Super class - superclass of entity, ie, org.apache.cayenne.art.auto._Artist
+## Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+## Classes available in template
+## object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+## stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+## entityUtils - class for entity "helper" functions: See org.apache.cayenne.gen.EntityUtils
+## importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+## superClassName
+## superPackageName
+## subClassName
+## subPackageName
+## baseClassName
+## basePackageName
+##
+##
+${importUtils.setPackage($superPackageName)}##
+${importUtils.addReservedType("${$superPackageName}.${superClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+#if((${object.DeclaredAttributes} && !${object.DeclaredAttributes.isEmpty()}) || (${object.DeclaredRelationships} && !${object.DeclaredRelationships.isEmpty()}))
+${importUtils.addType('org.apache.cayenne.exp.Property')}##
+#end
+#foreach( $attr in ${object.DeclaredAttributes} )
+$importUtils.addType(${attr.Type})##
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+$importUtils.addType(${rel.TargetEntity.ClientClassName})##
+#if(${rel.CollectionType})
+$importUtils.addType(${rel.CollectionType})##
+#end
+#end
+#if( ${entityUtils.hasToOneDeclaredRelationships()} )
+${importUtils.addType('org.apache.cayenne.ValueHolder')}##
+${importUtils.addType('org.apache.cayenne.util.PersistentObjectHolder')}##
+#end
+#if( ${entityUtils.hasToManyDeclaredRelationships()} )
+${importUtils.addType('org.apache.cayenne.util.PersistentObjectList')}##
+#end
+${importUtils.generate()}
+
+/**
+ * A generated persistent class mapped as "${object.name}" Cayenne entity. It is a good idea to
+ * avoid changing this class manually, since it will be overwritten next time code is
+ * regenerated. If you need to make any customizations, put them in a subclass.
+ */
+public abstract class ${superClassName} extends ${baseClassName} {
+
+## Create ivars names
+#if( $createPropertyNames )
+#foreach( $attr in ${object.DeclaredAttributes} )
+ public static final String ${stringUtils.capitalizedAsConstant($attr.Name)}_PROPERTY = "${attr.Name}";
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+ public static final String ${stringUtils.capitalizedAsConstant($rel.Name)}_PROPERTY = "${rel.Name}";
+#end
+
+#end
+## Create Properties
+#foreach( $attr in ${object.DeclaredAttributes} )
+ #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ${rel.CollectionType} == "java.util.Map")
+ #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClientClassName)>" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#else
+ #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClientClassName)>" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#else
+ #set( $type = "$importUtils.formatJavaType(${rel.TargetEntity.ClassName})" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#end
+
+## Create ivars
+#foreach( $attr in ${object.DeclaredAttributes} )
+ protected $importUtils.formatJavaType(${attr.Type}) ${attr.Name};
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ${rel.CollectionType} == "java.util.Map")
+ protected $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClientClassName)> ${rel.Name};
+#else
+ protected $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClientClassName)> ${rel.Name};
+#end
+#else
+ protected ValueHolder ${rel.Name};
+#end
+#end
+
+## Create attribute set/get methods
+#foreach( $attr in ${object.DeclaredAttributes} )
+#if ( $importUtils.isBoolean(${attr.Type}) )
+ public boolean is${stringUtils.capitalized($attr.Name)}() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${attr.Name}", false);
+ }
+
+ return ${attr.Name};
+ }
+#else
+ public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${attr.Name}", false);
+ }
+
+ return ${attr.Name};
+ }
+#end
+#if ("true" != "${object.isReadOnly()}")
+ public void set${stringUtils.capitalized($attr.Name)}($importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name})) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${attr.Name}", false);
+ }
+
+ Object oldValue = this.${stringUtils.formatVariableName($attr.Name)};
+ // notify objectContext about simple property change
+ if(objectContext != null) {
+ objectContext.propertyChanged(this, "${attr.Name}", oldValue, $stringUtils.formatVariableName(${attr.Name}));
+ }
+
+ this.${stringUtils.formatVariableName($attr.Name)} = ${stringUtils.formatVariableName($attr.Name)};
+ }
+#end
+
+#end
+##
+##
+## Create list add/remove/get methods
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ${rel.CollectionType} == "java.util.Map")
+ public $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClientClassName)> get${stringUtils.capitalized($rel.Name)}() {
+#else
+ public $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClientClassName)> get${stringUtils.capitalized($rel.Name)}() {
+#end
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+#if ( ${rel.CollectionType} == "java.util.Map")
+ throw new RuntimeException("Map relationships cannot be accessed for transient objects");
+#else
+ this.$rel.Name = new PersistentObjectList(this, "${rel.Name}");
+#end
+ }
+
+ return ${rel.Name};
+ }
+#if ( ! $rel.ReadOnly )
+#if ( ${rel.CollectionType} == "java.util.Map")
+ public void addTo${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClientClassName}) object) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+ throw new RuntimeException("Map relationships cannot be accessed for transient objects");
+ }
+
+ this.${rel.Name}.put(getMapKey("${rel.Name}", object), object);
+ }
+ public void removeFrom${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClientClassName}) object) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+ throw new RuntimeException("Map relationships cannot be accessed for transient objects");
+ }
+
+ this.${rel.Name}.remove(getMapKey("${rel.Name}", object));
+ }
+#else
+ public void addTo${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClientClassName}) object) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+ this.$rel.Name = new PersistentObjectList(this, "${rel.Name}");
+ }
+
+ this.${rel.Name}.add(object);
+ }
+ public void removeFrom${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClientClassName}) object) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+ this.$rel.Name = new PersistentObjectList(this, "${rel.Name}");
+ }
+
+ this.${rel.Name}.remove(object);
+ }
+#end
+#end
+#else
+ public $importUtils.formatJavaType(${rel.TargetEntity.ClientClassName}) get${stringUtils.capitalized($rel.Name)}() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+ this.$rel.Name = new PersistentObjectHolder(this, "$rel.Name");
+ }
+
+ return ($importUtils.formatJavaType(${rel.TargetEntity.ClientClassName})) ${rel.Name}.getValue();
+ }
+#if ( !${object.isReadOnly()} && !$rel.ReadOnly )
+ public void set${stringUtils.capitalized($rel.Name)}(${importUtils.formatJavaType($rel.TargetEntity.ClientClassName)} $stringUtils.formatVariableName(${rel.Name})) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "${rel.Name}", true);
+ } else if (this.$rel.Name == null) {
+ this.$rel.Name = new PersistentObjectHolder(this, "$rel.Name");
+ }
+
+ // note how we notify ObjectContext of change BEFORE the object is actually
+ // changed... this is needed to take a valid current snapshot
+ Object oldValue = this.${rel.Name}.getValueDirectly();
+ if (objectContext != null) {
+ objectContext.propertyChanged(this, "$rel.Name", oldValue, $stringUtils.formatVariableName(${rel.Name}));
+ }
+
+ this.${stringUtils.formatVariableName($rel.Name)}.setValue(${stringUtils.formatVariableName($rel.Name)});
+ }
+#end
+#end
+
+#end
+##callback methods
+#foreach( $cbname in ${entityUtils.callbackNames})
+ protected abstract void ${cbname}();
+
+#end
+}