001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.meta;
020:
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Member;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.Modifier;
025: import java.security.AccessController;
026: import java.security.PrivilegedActionException;
027: import java.util.List;
028:
029: import org.apache.openjpa.enhance.PCRegistry;
030: import org.apache.openjpa.enhance.Reflection;
031: import org.apache.openjpa.lib.log.Log;
032: import org.apache.openjpa.lib.util.J2DoPrivHelper;
033: import org.apache.openjpa.lib.util.Localizer;
034: import org.apache.openjpa.util.InternalException;
035: import org.apache.openjpa.util.OpenJPAException;
036: import org.apache.openjpa.util.UserException;
037:
038: /**
039: * Abstract metadata defaults.
040: *
041: * @author Abe White
042: */
043: public abstract class AbstractMetaDataDefaults implements
044: MetaDataDefaults {
045:
046: private static final Localizer _loc = Localizer
047: .forPackage(AbstractMetaDataDefaults.class);
048:
049: private int _access = ClassMetaData.ACCESS_FIELD;
050: private int _identity = ClassMetaData.ID_UNKNOWN;
051: private boolean _ignore = true;
052: private boolean _interface = true;
053: private boolean _pcRegistry = true;
054: private int _callback = CALLBACK_RETHROW;
055: private boolean _unwrapped = false;
056:
057: /**
058: * Whether to attempt to use the information from registered classes
059: * to populate metadata defaults. Defaults to true.
060: */
061: public boolean getUsePCRegistry() {
062: return _pcRegistry;
063: }
064:
065: /**
066: * Whether to attempt to use the information from registered classes
067: * to populate metadata defaults. Defaults to true.
068: */
069: public void setUsePCRegistry(boolean pcRegistry) {
070: _pcRegistry = pcRegistry;
071: }
072:
073: /**
074: * The default access type for base classes with ACCESS_UNKNOWN.
075: * ACCESS_FIELD by default.
076: */
077: public int getDefaultAccessType() {
078: return _access;
079: }
080:
081: /**
082: * The default access type for base classes with ACCESS_UNKNOWN.
083: * ACCESS_FIELD by default.
084: */
085: public void setDefaultAccessType(int access) {
086: _access = access;
087: }
088:
089: /**
090: * The default identity type for unmapped classes without primary
091: * key fields. ID_UNKNOWN by default.
092: */
093: public int getDefaultIdentityType() {
094: return _identity;
095: }
096:
097: /**
098: * The default identity type for unmapped classes without primary
099: * key fields. ID_UNKNOWN by default.
100: */
101: public void setDefaultIdentityType(int identity) {
102: _identity = identity;
103: }
104:
105: public int getCallbackMode() {
106: return _callback;
107: }
108:
109: public void setCallbackMode(int mode) {
110: _callback = mode;
111: }
112:
113: public void setCallbackMode(int mode, boolean on) {
114: if (on)
115: _callback |= mode;
116: else
117: _callback &= ~mode;
118: }
119:
120: public boolean getCallbacksBeforeListeners(int type) {
121: return false;
122: }
123:
124: public boolean isDeclaredInterfacePersistent() {
125: return _interface;
126: }
127:
128: public void setDeclaredInterfacePersistent(boolean pers) {
129: _interface = pers;
130: }
131:
132: public boolean isDataStoreObjectIdFieldUnwrapped() {
133: return _unwrapped;
134: }
135:
136: public void setDataStoreObjectIdFieldUnwrapped(boolean unwrapped) {
137: _unwrapped = unwrapped;
138: }
139:
140: public boolean getIgnoreNonPersistent() {
141: return _ignore;
142: }
143:
144: public void setIgnoreNonPersistent(boolean ignore) {
145: _ignore = ignore;
146: }
147:
148: public void populate(ClassMetaData meta, int access) {
149: if (meta.getDescribedType() == Object.class)
150: return;
151:
152: if (access == ClassMetaData.ACCESS_UNKNOWN) {
153: // we do not allow using both field and method access at
154: // the same time
155: access = getAccessType(meta);
156: if ((access & ClassMetaData.ACCESS_FIELD) != 0
157: && (access & ClassMetaData.ACCESS_PROPERTY) != 0) {
158: List fields = getFieldAccessNames(meta);
159: List props = getPropertyAccessNames(meta);
160: if (fields != null || props != null)
161: throw new UserException(_loc.get(
162: "access-field-and-prop-hints", meta
163: .getDescribedType().getName(),
164: fields, props));
165: else
166: throw new UserException(_loc.get(
167: "access-field-and-prop", meta
168: .getDescribedType().getName()));
169: }
170: }
171: meta.setAccessType(access);
172:
173: Log log = meta.getRepository().getLog();
174: if (log.isTraceEnabled())
175: log.trace(_loc.get("gen-meta", meta));
176: if (!_pcRegistry || !populateFromPCRegistry(meta)) {
177: if (log.isTraceEnabled())
178: log.trace(_loc.get("meta-reflect"));
179: populateFromReflection(meta);
180: }
181: }
182:
183: /**
184: * Populate initial field data. Does nothing by default.
185: */
186: protected void populate(FieldMetaData fmd) {
187: }
188:
189: /**
190: * Populate the given metadata using the {@link PCRegistry}.
191: */
192: private boolean populateFromPCRegistry(ClassMetaData meta) {
193: Class cls = meta.getDescribedType();
194: if (!PCRegistry.isRegistered(cls))
195: return false;
196: try {
197: String[] fieldNames = PCRegistry.getFieldNames(cls);
198: Class[] fieldTypes = PCRegistry.getFieldTypes(cls);
199: Member member;
200: FieldMetaData fmd;
201: for (int i = 0; i < fieldNames.length; i++) {
202: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
203: member = (Field) AccessController
204: .doPrivileged(J2DoPrivHelper
205: .getDeclaredFieldAction(cls,
206: fieldNames[i]));
207: else
208: member = Reflection.findGetter(meta
209: .getDescribedType(), fieldNames[i], true);
210: fmd = meta.addDeclaredField(fieldNames[i],
211: fieldTypes[i]);
212: fmd.backingMember(member);
213: populate(fmd);
214: }
215: return true;
216: } catch (OpenJPAException ke) {
217: throw ke;
218: } catch (Exception e) {
219: if (e instanceof PrivilegedActionException)
220: e = ((PrivilegedActionException) e).getException();
221: throw new UserException(e);
222: }
223: }
224:
225: /**
226: * Generate the given metadata using reflection.
227: */
228: private void populateFromReflection(ClassMetaData meta) {
229: Member[] members;
230: boolean iface = meta.getDescribedType().isInterface();
231: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD
232: && !iface)
233: members = (Field[]) AccessController
234: .doPrivileged(J2DoPrivHelper
235: .getDeclaredFieldsAction(meta
236: .getDescribedType()));
237: else
238: members = (Method[]) AccessController
239: .doPrivileged(J2DoPrivHelper
240: .getDeclaredMethodsAction(meta
241: .getDescribedType()));
242:
243: int mods;
244: String name;
245: boolean def;
246: FieldMetaData fmd;
247: for (int i = 0; i < members.length; i++) {
248: mods = members[i].getModifiers();
249: if (Modifier.isStatic(mods) || Modifier.isFinal(mods))
250: continue;
251:
252: name = getFieldName(members[i]);
253: if (name == null || isReservedFieldName(name))
254: continue;
255:
256: def = isDefaultPersistent(meta, members[i], name);
257: if (!def && _ignore)
258: continue;
259:
260: // passed the tests; persistent type -- we construct with
261: // Object.class because setting backing member will set proper
262: // type anyway
263: fmd = meta.addDeclaredField(name, Object.class);
264: fmd.backingMember(members[i]);
265: if (!def) {
266: fmd.setExplicit(true);
267: fmd.setManagement(FieldMetaData.MANAGE_NONE);
268: }
269: populate(fmd);
270: }
271: }
272:
273: /**
274: * Return the access type of the given metadata. May be a bitwise
275: * combination of field and property access constants, or ACCESS_UNKNOWN.
276: * Returns ACCESS_FIELD by default.
277: */
278: protected int getAccessType(ClassMetaData meta) {
279: if (meta.getDescribedType().isInterface())
280: return ClassMetaData.ACCESS_PROPERTY;
281: else
282: return ClassMetaData.ACCESS_FIELD;
283: }
284:
285: /**
286: * Return the list of fields in <code>meta</code> that use field access,
287: * or <code>null</code> if a list of fields is unobtainable. An empty list
288: * should be returned if the list of fields is obtainable, but there
289: * happens to be no field access in <code>meta</code>.
290: *
291: * This is used for error reporting purposes only, so need not be efficient.
292: *
293: * This implementation returns <code>null</code>.
294: */
295: protected List getFieldAccessNames(ClassMetaData meta) {
296: return null;
297: }
298:
299: /**
300: * Return the list of methods in <code>meta</code> that use property access,
301: * or <code>null</code> if a list of methods is unobtainable. An empty list
302: * should be returned if the list of methods is obtainable, but there
303: * happens to be no property access in <code>meta</code>.
304: *
305: * This is used for error reporting purposes only, so need not be efficient.
306: *
307: * This implementation returns <code>null</code>.
308: */
309: protected List getPropertyAccessNames(ClassMetaData meta) {
310: return null;
311: }
312:
313: /**
314: * Return the field name for the given member. This will only be invoked
315: * on members of the right type (field vs. method). Return null if the
316: * member cannot be managed. Default behavior: For fields, returns the
317: * field name. For getter methods, returns the minus "get" or "is" with
318: * the next letter lower-cased. For other methods, returns null.
319: */
320: protected String getFieldName(Member member) {
321: if (member instanceof Field)
322: return member.getName();
323:
324: Method meth = (Method) member;
325: if (meth.getReturnType() == void.class
326: || meth.getParameterTypes().length != 0)
327: return null;
328:
329: String name = meth.getName();
330: if (name.startsWith("get") && name.length() > 3)
331: name = name.substring(3);
332: else if ((meth.getReturnType() == boolean.class || meth
333: .getReturnType() == Boolean.class)
334: && name.startsWith("is") && name.length() > 2)
335: name = name.substring(2);
336: else
337: return null;
338:
339: if (name.length() == 1)
340: return name.toLowerCase();
341: return Character.toLowerCase(name.charAt(0))
342: + name.substring(1);
343: }
344:
345: /**
346: * Returns true if the given field name is reserved for unmanaged fields.
347: */
348: protected boolean isReservedFieldName(String name) {
349: // names used by enhancers
350: return name.startsWith("openjpa") || name.startsWith("jdo");
351: }
352:
353: /**
354: * Return true if the given member is persistent by default. This will
355: * only be invoked on members of the right type (field vs. method).
356: * Returns false if member is static or final by default.
357: *
358: * @param name the field name from {@link #getFieldName}
359: */
360: protected abstract boolean isDefaultPersistent(ClassMetaData meta,
361: Member member, String name);
362:
363: public Member getBackingMember(FieldMetaData fmd) {
364: if (fmd == null)
365: return null;
366: try {
367: //### note that we might not have access to declaring metadata yet
368: //### (this could be used during parse), so we have to settle for
369: //### defining. could cause problems if maps a superclass field
370: //### where the superclass uses a different access type
371: if (fmd.getDefiningMetaData().getAccessType() == ClassMetaData.ACCESS_FIELD)
372: return (Field) AccessController
373: .doPrivileged(J2DoPrivHelper
374: .getDeclaredFieldAction(fmd
375: .getDeclaringType(), fmd
376: .getName()));
377: return Reflection.findGetter(fmd.getDeclaringType(), fmd
378: .getName(), true);
379: } catch (OpenJPAException ke) {
380: throw ke;
381: } catch (Exception e) {
382: if (e instanceof PrivilegedActionException)
383: e = ((PrivilegedActionException) e).getException();
384: throw new InternalException(e);
385: }
386: }
387:
388: public Class getUnimplementedExceptionType() {
389: return UnsupportedOperationException.class;
390: }
391:
392: /**
393: * Helper method; returns true if the given class appears to be
394: * user-defined.
395: */
396: protected static boolean isUserDefined(Class cls) {
397: return cls != null && !cls.getName().startsWith("java.")
398: && !cls.getName().startsWith("javax.");
399: }
400: }
|