001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
005: *
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common Development
009: * and Distribution License("CDDL") (collectively, the "License"). You
010: * may not use this file except in compliance with the License. You can obtain
011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
013: * language governing permissions and limitations under the License.
014: *
015: * When distributing the software, include this License Header Notice in each
016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
017: * Sun designates this particular file as subject to the "Classpath" exception
018: * as provided by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the License
020: * Header, with the fields enclosed by brackets [] replaced by your own
021: * identifying information: "Portions Copyrighted [year]
022: * [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * If you wish your version of this file to be governed by only the CDDL or
027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
028: * elects to include this software in this distribution under the [CDDL or GPL
029: * Version 2] license." If you don't indicate a single choice of license, a
030: * recipient has the option to distribute your version of this file under
031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
032: * its licensees as provided above. However, if you add GPL Version 2 code
033: * and therefore, elected the GPL Version 2 license, then the option applies
034: * only if the new code is made subject to such option by the copyright
035: * holder.
036: */
037: package oracle.toplink.essentials.internal.queryframework;
038:
039: import java.security.AccessController;
040: import java.security.PrivilegedActionException;
041: import java.util.*;
042: import java.lang.reflect.*;
043:
044: import oracle.toplink.essentials.exceptions.*;
045: import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
046: import oracle.toplink.essentials.internal.security.PrivilegedMethodInvoker;
047: import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
048: import oracle.toplink.essentials.internal.security.PrivilegedGetMethod;
049:
050: /**
051: * <p><b>Purpose</b>: The abstract class for ContainerPolicy's whose container class implements
052: * a container interface.
053: * <p>
054: *
055: * @see CollectionContainerPolicy
056: * @see MapContainerPolicy
057: */
058: public abstract class InterfaceContainerPolicy extends ContainerPolicy {
059:
060: /** The concrete container class. */
061: protected Class containerClass;
062: protected String containerClassName;
063:
064: /** The method which will return a clone of an instance of the containerClass. */
065: protected transient Method cloneMethod;
066:
067: /**
068: * INTERNAL:
069: * Construct a new policy.
070: */
071: public InterfaceContainerPolicy() {
072: super ();
073: }
074:
075: /**
076: * INTERNAL:
077: * Construct a new policy for the specified class.
078: */
079: public InterfaceContainerPolicy(Class containerClass) {
080: setContainerClass(containerClass);
081: }
082:
083: /**
084: * INTERNAL:
085: * Construct a new policy for the specified class name.
086: */
087: public InterfaceContainerPolicy(String containerClassName) {
088: setContainerClassName(containerClassName);
089: }
090:
091: /**
092: * INTERNAL:
093: * Return a clone of the specified container.
094: */
095: public Object cloneFor(Object container) {
096: if (container == null) {
097: return null;
098: }
099:
100: try {
101: return invokeCloneMethodOn(getCloneMethod(), container);
102: } catch (IllegalArgumentException ex) {
103: // container may be a superclass of the concrete container class
104: // so we have to use the right clone method...
105: return invokeCloneMethodOn(getCloneMethod(container
106: .getClass()), container);
107: }
108: }
109:
110: /**
111: * INTERNAL:
112: * Convert all the class-name-based settings in this ContainerPolicy to actual class-based
113: * settings. This method is used when converting a project that has been built
114: * with class names to a project with classes.
115: * @param classLoader
116: */
117: public void convertClassNamesToClasses(ClassLoader classLoader) {
118: super .convertClassNamesToClasses(classLoader);
119: if (containerClassName == null) {
120: return;
121: }
122: Class containerClass = null;
123: try {
124: if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
125: try {
126: containerClass = (Class) AccessController
127: .doPrivileged(new PrivilegedClassForName(
128: containerClassName, true,
129: classLoader));
130: } catch (PrivilegedActionException exception) {
131: throw ValidationException
132: .classNotFoundWhileConvertingClassNames(
133: containerClassName, exception
134: .getException());
135: }
136: } else {
137: containerClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper
138: .getClassForName(containerClassName, true,
139: classLoader);
140: }
141: } catch (ClassNotFoundException exc) {
142: throw ValidationException
143: .classNotFoundWhileConvertingClassNames(
144: containerClassName, exc);
145: }
146: setContainerClass(containerClass);
147: };
148:
149: /**
150: * INTERNAL:
151: * Return the 'clone()' Method for the container class.
152: * Lazy initialization is used, so we can serialize these things.
153: */
154: public Method getCloneMethod() {
155: if (cloneMethod == null) {
156: setCloneMethod(getCloneMethod(getContainerClass()));
157: }
158: return cloneMethod;
159: }
160:
161: /**
162: * INTERNAL:
163: * Return the 'clone()' Method for the specified class.
164: * Return null if the method does not exist anywhere in the hierarchy
165: */
166: protected Method getCloneMethod(Class javaClass) {
167: try {
168: // This must not be set "accessible" - clone() must be public, and some JVM's do not allow access to JDK classes.
169: if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
170: try {
171: return (Method) AccessController
172: .doPrivileged(new PrivilegedGetMethod(
173: javaClass, "clone", (Class[]) null,
174: false));
175: } catch (PrivilegedActionException exception) {
176: throw QueryException
177: .methodDoesNotExistInContainerClass(
178: "clone", javaClass);
179: }
180: } else {
181: return PrivilegedAccessHelper.getMethod(javaClass,
182: "clone", (Class[]) null, false);
183: }
184: } catch (NoSuchMethodException ex) {
185: throw QueryException.methodDoesNotExistInContainerClass(
186: "clone", javaClass);
187: }
188: }
189:
190: /**
191: * INTERNAL:
192: * Returns the container class to be used with this policy.
193: */
194: public Class getContainerClass() {
195: return containerClass;
196: }
197:
198: public String getContainerClassName() {
199: if ((containerClassName == null) && (containerClass != null)) {
200: containerClassName = containerClass.getName();
201: }
202: return containerClassName;
203: }
204:
205: public abstract Class getInterfaceType();
206:
207: /**
208: * INTERNAL:
209: * Return whether the iterator has more objects,
210: */
211: public boolean hasNext(Object iterator) {
212: return ((Iterator) iterator).hasNext();
213: }
214:
215: /**
216: * INTERNAL:
217: * Invoke the specified clone method on the container,
218: * handling the necessary exceptions.
219: */
220: protected Object invokeCloneMethodOn(Method method, Object container) {
221: try {
222: if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
223: try {
224: return AccessController
225: .doPrivileged(new PrivilegedMethodInvoker(
226: method, container, (Object[]) null));
227: } catch (PrivilegedActionException exception) {
228: Exception throwableException = exception
229: .getException();
230: if (throwableException instanceof IllegalAccessException) {
231: throw QueryException
232: .cannotAccessMethodOnObject(method,
233: container);
234: } else {
235: throw QueryException.methodInvocationFailed(
236: method, container, throwableException);
237: }
238: }
239: } else {
240: return PrivilegedAccessHelper.invokeMethod(method,
241: container, (Object[]) null);
242: }
243: } catch (IllegalAccessException ex1) {
244: throw QueryException.cannotAccessMethodOnObject(method,
245: container);
246: } catch (InvocationTargetException ex2) {
247: throw QueryException.methodInvocationFailed(method,
248: container, ex2);
249: }
250: }
251:
252: /**
253: * INTERNAL:
254: * Validate the container type.
255: */
256: public boolean isValidContainerType(Class containerType) {
257: return oracle.toplink.essentials.internal.helper.Helper
258: .classImplementsInterface(containerType,
259: getInterfaceType());
260: }
261:
262: /**
263: * INTERNAL:
264: * Return the next object on the queue.
265: * Valid for some subclasses only.
266: */
267: protected Object next(Object iterator) {
268: return ((Iterator) iterator).next();
269: }
270:
271: /**
272: * INTERNAL:
273: * Set the Method that will return a clone of an instance of the containerClass.
274: */
275: public void setCloneMethod(Method cloneMethod) {
276: this .cloneMethod = cloneMethod;
277: }
278:
279: /**
280: * INTERNAL:
281: * Set the class to use as the container.
282: */
283: public void setContainerClass(Class containerClass) {
284: this .containerClass = containerClass;
285: initializeConstructor();
286: }
287:
288: public void setContainerClassName(String containerClassName) {
289: this .containerClassName = containerClassName;
290: }
291:
292: protected Object toStringInfo() {
293: return this.getContainerClass();
294: }
295: }
|