Source code: org/objectstyle/cayenne/project/NamedObjectFactory.java
1 /* ====================================================================
2 *
3 * The ObjectStyle Group Software License, Version 1.0
4 *
5 * Copyright (c) 2002-2003 The ObjectStyle Group
6 * and individual authors of the software. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution, if
21 * any, must include the following acknowlegement:
22 * "This product includes software developed by the
23 * ObjectStyle Group (http://objectstyle.org/)."
24 * Alternately, this acknowlegement may appear in the software itself,
25 * if and wherever such third-party acknowlegements normally appear.
26 *
27 * 4. The names "ObjectStyle Group" and "Cayenne"
28 * must not be used to endorse or promote products derived
29 * from this software without prior written permission. For written
30 * permission, please contact andrus@objectstyle.org.
31 *
32 * 5. Products derived from this software may not be called "ObjectStyle"
33 * nor may "ObjectStyle" appear in their names without prior written
34 * permission of the ObjectStyle Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the ObjectStyle Group. For more
52 * information on the ObjectStyle Group, please see
53 * <http://objectstyle.org/>.
54 *
55 */
56 package org.objectstyle.cayenne.project;
57
58 import java.util.HashMap;
59 import java.util.Iterator;
60 import java.util.Map;
61
62 import org.objectstyle.cayenne.access.DataDomain;
63 import org.objectstyle.cayenne.access.DataNode;
64 import org.objectstyle.cayenne.conf.Configuration;
65 import org.objectstyle.cayenne.dba.TypesMapping;
66 import org.objectstyle.cayenne.map.DataMap;
67 import org.objectstyle.cayenne.map.DbAttribute;
68 import org.objectstyle.cayenne.map.DbEntity;
69 import org.objectstyle.cayenne.map.DbRelationship;
70 import org.objectstyle.cayenne.map.DerivedDbAttribute;
71 import org.objectstyle.cayenne.map.DerivedDbEntity;
72 import org.objectstyle.cayenne.map.Entity;
73 import org.objectstyle.cayenne.map.ObjAttribute;
74 import org.objectstyle.cayenne.map.ObjEntity;
75 import org.objectstyle.cayenne.map.ObjRelationship;
76 import org.objectstyle.cayenne.map.Procedure;
77 import org.objectstyle.cayenne.map.ProcedureParameter;
78 import org.objectstyle.cayenne.map.Relationship;
79
80 /**
81 * Factory class that generates various Cayenne objects with
82 * default names that are unique in their corresponding context.
83 * Supports creation of the following
84 * objects:
85 * <ul>
86 * <li>DataMap</li>
87 * <li>ObjEntity</li>
88 * <li>ObjAttribute</li>
89 * <li>ObjRelationship</li>
90 * <li>DbEntity</li>
91 * <li>DerivedDbEntity</li>
92 * <li>DbAttribute</li>
93 * <li>DerivedDbAttribute</li>
94 * <li>DbRelationship</li>
95 * <li>DataNode</li>
96 * <li>DataDomain</li>
97 * <li>Procedure</li>
98 * <li>ProcedureParameter</li>
99 * </ul>
100 *
101 * This is a helper class used mostly by GUI and database
102 * reengineering classes.
103 *
104 * @author Andrei Adamchik
105 */
106 public abstract class NamedObjectFactory {
107 private static final Map factories = new HashMap();
108
109 static {
110 factories.put(DataMap.class, new DataMapFactory());
111 factories.put(ObjEntity.class, new ObjEntityFactory());
112 factories.put(DbEntity.class, new DbEntityFactory());
113 factories.put(DerivedDbEntity.class, new DerivedDbEntityFactory());
114 factories.put(ObjAttribute.class, new ObjAttributeFactory());
115 factories.put(DbAttribute.class, new DbAttributeFactory());
116 factories.put(DerivedDbAttribute.class, new DerivedDbAttributeFactory());
117 factories.put(DataNode.class, new DataNodeFactory());
118 factories.put(DbRelationship.class, new DbRelationshipFactory(null, false));
119 factories.put(ObjRelationship.class, new ObjRelationshipFactory(null, false));
120 factories.put(DataDomain.class, new DataDomainFactory());
121 factories.put(Procedure.class, new ProcedureFactory());
122 factories.put(ProcedureParameter.class, new ProcedureParameterFactory());
123 }
124
125 public static String createName(Class objectClass, Object namingContext) {
126 return ((NamedObjectFactory) factories.get(objectClass)).makeName(namingContext);
127 }
128
129 /**
130 * Creates an object using an appropriate factory class.
131 * If no factory is found for the object, NullPointerException is
132 * thrown.
133 *
134 * <p><i>Note that newly created object is not added to the parent.
135 * This behavior can be changed later.</i></p>
136 */
137 public static Object createObject(Class objectClass, Object namingContext) {
138 return ((NamedObjectFactory) factories.get(objectClass)).makeObject(
139 namingContext);
140 }
141
142 /**
143 * Creates a relationship using an appropriate factory class.
144 * If no factory is found for the object, NullPointerException is
145 * thrown.
146 *
147 * <p><i>Note that newly created object is not added to the parent.
148 * This behavior can be changed later.</i></p>
149 */
150 public static Relationship createRelationship(
151 Entity srcEnt,
152 Entity targetEnt,
153 boolean toMany) {
154 NamedObjectFactory factory =
155 (srcEnt instanceof ObjEntity)
156 ? new ObjRelationshipFactory(targetEnt, toMany)
157 : new DbRelationshipFactory(targetEnt, toMany);
158 return (Relationship) factory.makeObject(srcEnt);
159 }
160
161 /**
162 * Creates a unique name for the new object and constructs
163 * this object.
164 */
165 protected synchronized String makeName(Object namingContext) {
166 int c = 1;
167 String name = null;
168 do {
169 name = nameBase() + c++;
170 }
171 while (isNameInUse(name, namingContext));
172
173 return name;
174 }
175
176 /**
177 * Creates a unique name for the new object and constructs
178 * this object.
179 */
180 protected Object makeObject(Object namingContext) {
181 return create(makeName(namingContext), namingContext);
182 }
183
184 /** Returns a base default name, like "UntitledEntity", etc. */
185 protected abstract String nameBase();
186
187 /** Internal factory method. Invoked after the name is figured out. */
188 protected abstract Object create(String name, Object namingContext);
189
190 /**
191 * Checks if the name is already taken by another sibling
192 * in the same context.
193 */
194 protected abstract boolean isNameInUse(String name, Object namingContext);
195
196 // concrete factories
197 static class DataDomainFactory extends NamedObjectFactory {
198 protected String nameBase() {
199 return "UntitledDomain";
200 }
201
202 protected Object create(String name, Object namingContext) {
203 return new DataDomain(name);
204 }
205
206 protected boolean isNameInUse(String name, Object namingContext) {
207 Configuration config = (Configuration) namingContext;
208 return config.getDomain(name) != null;
209 }
210 }
211
212 static class DataMapFactory extends NamedObjectFactory {
213 protected String nameBase() {
214 return "UntitledMap";
215 }
216
217 protected Object create(String name, Object namingContext) {
218 return new DataMap(name);
219 }
220
221 protected boolean isNameInUse(String name, Object namingContext) {
222 // null context is a situation when DataMap is a
223 // top level object of the project
224 if (namingContext == null) {
225 return false;
226 }
227
228 DataDomain domain = (DataDomain) namingContext;
229 return domain.getMap(name) != null;
230 }
231 }
232
233 static class ObjEntityFactory extends NamedObjectFactory {
234 protected String nameBase() {
235 return "UntitledObjEntity";
236 }
237
238 protected Object create(String name, Object namingContext) {
239 return new ObjEntity(name);
240 }
241
242 protected boolean isNameInUse(String name, Object namingContext) {
243 DataMap map = (DataMap) namingContext;
244 return map.getObjEntity(name) != null;
245 }
246 }
247
248 static class DbEntityFactory extends NamedObjectFactory {
249 protected String nameBase() {
250 return "UntitledDbEntity";
251 }
252
253 protected Object create(String name, Object namingContext) {
254 return new DbEntity(name);
255 }
256
257 protected boolean isNameInUse(String name, Object namingContext) {
258 DataMap map = (DataMap) namingContext;
259 return map.getDbEntity(name) != null;
260 }
261 }
262
263 static class ProcedureParameterFactory extends NamedObjectFactory {
264 protected String nameBase() {
265 return "UntitledProcedureParameter";
266 }
267
268 protected Object create(String name, Object namingContext) {
269 return new ProcedureParameter(name);
270 }
271
272 protected boolean isNameInUse(String name, Object namingContext) {
273
274 // it doesn't matter if we create a parameter with
275 // a duplicate name.. parameters are positional anyway..
276 // still try to use unique names for visual consistency
277 Procedure procedure = (Procedure) namingContext;
278 Iterator it = procedure.getCallParameters().iterator();
279 while (it.hasNext()) {
280 ProcedureParameter parameter = (ProcedureParameter) it.next();
281 if (name.equals(parameter.getName())) {
282 return true;
283 }
284 }
285
286 return false;
287 }
288 }
289
290 static class ProcedureFactory extends NamedObjectFactory {
291 protected String nameBase() {
292 return "UntitledProcedure";
293 }
294
295 protected Object create(String name, Object namingContext) {
296 return new Procedure(name);
297 }
298
299 protected boolean isNameInUse(String name, Object namingContext) {
300 DataMap map = (DataMap) namingContext;
301 return map.getProcedure(name) != null;
302 }
303 }
304
305 static class DerivedDbEntityFactory extends DbEntityFactory {
306 protected Object create(String name, Object namingContext) {
307 return new DerivedDbEntity(name);
308 }
309 }
310
311 static class ObjAttributeFactory extends NamedObjectFactory {
312 protected String nameBase() {
313 return "UntitledAttr";
314 }
315
316 protected Object create(String name, Object namingContext) {
317 return new ObjAttribute(name, null, (ObjEntity) namingContext);
318 }
319
320 protected boolean isNameInUse(String name, Object namingContext) {
321 Entity ent = (Entity) namingContext;
322 return ent.getAttribute(name) != null;
323 }
324 }
325
326 static class DbAttributeFactory extends ObjAttributeFactory {
327 protected Object create(String name, Object namingContext) {
328 return new DbAttribute(
329 name,
330 TypesMapping.NOT_DEFINED,
331 (DbEntity) namingContext);
332 }
333 }
334
335 static class DerivedDbAttributeFactory extends ObjAttributeFactory {
336 protected Object create(String name, Object namingContext) {
337 return new DerivedDbAttribute(
338 name,
339 TypesMapping.NOT_DEFINED,
340 (DbEntity) namingContext,
341 DerivedDbAttribute.ATTRIBUTE_TOKEN);
342 }
343 }
344
345 static class DataNodeFactory extends NamedObjectFactory {
346 protected String nameBase() {
347 return "UntitledDataNode";
348 }
349
350 protected Object create(String name, Object namingContext) {
351 return new DataNode(name);
352 }
353
354 protected boolean isNameInUse(String name, Object namingContext) {
355 DataDomain domain = (DataDomain) namingContext;
356 return domain.getNode(name) != null;
357 }
358 }
359
360 static class ObjRelationshipFactory extends NamedObjectFactory {
361 protected Entity target;
362 protected boolean toMany;
363
364 public ObjRelationshipFactory(Entity target, boolean toMany) {
365 this.target = target;
366 this.toMany = toMany;
367 }
368
369 protected Object create(String name, Object namingContext) {
370 return new ObjRelationship(name);
371 }
372
373 protected boolean isNameInUse(String name, Object namingContext) {
374 Entity ent = (Entity) namingContext;
375 return ent.getRelationship(name) != null;
376 }
377
378 /**
379 * Returns generated name for the ObjRelationships.
380 * For to-one case and entity name "xxxx" it generates name "toXxxx".
381 * For to-many case and entity name "Xxxx" it generates name "xxxxArray".
382 */
383 protected String nameBase() {
384 if (target == null) {
385 return "UntitledRel";
386 }
387
388 String name = target.getName();
389 return (toMany)
390 ? Character.toLowerCase(name.charAt(0)) + name.substring(1) + "Array"
391 : "to" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
392 }
393 }
394
395 static class DbRelationshipFactory extends ObjRelationshipFactory {
396 public DbRelationshipFactory(Entity target, boolean toMany) {
397 super(target, toMany);
398 }
399
400 protected Object create(String name, Object namingContext) {
401 return new DbRelationship(name);
402 }
403
404 /**
405 * Returns generated name for the DbRelationships.
406 * For to-one case it generates name "TO_XXXX".
407 * For to-many case it generates name "XXXX_ARRAY".
408 */
409 protected String nameBase() {
410 if (target == null) {
411 return "UntitledRel";
412 }
413
414 String name = target.getName();
415 return (toMany) ? name + "_ARRAY" : "TO_" + name;
416 }
417 }
418 }