001: /*
002: * $Id: DefaultPageFactory.java 460098 2006-04-01 21:57:15Z jdonnerstag $
003: * $Revision: 460098 $ $Date: 2006-04-01 23:57:15 +0200 (Sat, 01 Apr 2006) $
004: *
005: * ==============================================================================
006: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
007: * use this file except in compliance with the License. You may obtain a copy of
008: * 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, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations under
016: * the License.
017: */
018: package wicket.session;
019:
020: import java.lang.reflect.Constructor;
021: import java.lang.reflect.InvocationTargetException;
022: import java.util.Map;
023:
024: import wicket.AbortException;
025: import wicket.IPageFactory;
026: import wicket.Page;
027: import wicket.PageParameters;
028: import wicket.WicketRuntimeException;
029: import wicket.authorization.AuthorizationException;
030: import wicket.markup.MarkupException;
031: import wicket.util.concurrent.ConcurrentHashMap;
032:
033: /**
034: * A factory that constructs Pages.
035: *
036: * @see wicket.settings.ISessionSettings#setPageFactory(IPageFactory)
037: * @see IPageFactory
038: *
039: * @author Juergen Donnerstag
040: * @author Jonathan Locke
041: */
042: public final class DefaultPageFactory implements IPageFactory {
043: /** Map of Constructors for Page subclasses */
044: private final Map constructorForClass = new ConcurrentHashMap();
045:
046: /**
047: * @see IPageFactory#newPage(Class)
048: */
049: public final Page newPage(final Class pageClass) {
050: try {
051: // throw an exception in case default constructor is missing
052: // => improved error message
053: pageClass.getConstructor((Class[]) null);
054:
055: return (Page) pageClass.newInstance();
056: } catch (NoSuchMethodException e) {
057: // a bit of a hack here..
058: Constructor constructor = constructor(pageClass,
059: PageParameters.class);
060: if (constructor != null) {
061: return newPage(constructor, new PageParameters());
062: } else {
063: throw new WicketRuntimeException(
064: "Unable to create page from "
065: + pageClass
066: + ". Class does not have a default contructor",
067: e);
068: }
069: } catch (InstantiationException e) {
070: throw new WicketRuntimeException(
071: "Unable to create page from " + pageClass, e);
072: } catch (IllegalAccessException e) {
073: throw new WicketRuntimeException(
074: "Unable to create page from " + pageClass, e);
075: }
076: }
077:
078: /**
079: * @see IPageFactory#newPage(Class, PageParameters)
080: */
081: public final Page newPage(final Class pageClass,
082: final PageParameters parameters) {
083: // Try to get constructor that takes PageParameters
084: Constructor constructor = constructor(pageClass,
085: PageParameters.class);
086:
087: // If we got a PageParameters constructor
088: if (constructor != null) {
089: // return new Page(parameters)
090: return newPage(constructor, parameters);
091: }
092:
093: // Always try default constructor if one exists
094: return newPage(pageClass);
095: }
096:
097: /**
098: * Looks up a one-arg Page constructor by class and argument type.
099: *
100: * @param pageClass
101: * The class of page
102: * @param argumentType
103: * The argument type
104: * @return The page constructor, or null if no one-arg constructor can be
105: * found taking the given argument type.
106: */
107: private final Constructor constructor(final Class pageClass,
108: final Class argumentType) {
109: // Get constructor for page class from cache
110: Constructor constructor = (Constructor) constructorForClass
111: .get(pageClass);
112:
113: // Need to look up?
114: if (constructor == null) {
115: try {
116: // Try to find the constructor
117: constructor = pageClass
118: .getConstructor(new Class[] { argumentType });
119:
120: // Store it in the cache
121: constructorForClass.put(pageClass, constructor);
122: } catch (NoSuchMethodException e) {
123: return null;
124: }
125: }
126:
127: return constructor;
128: }
129:
130: /**
131: * Creates a new Page using the given constructor and argument.
132: *
133: * @param constructor
134: * The constructor to invoke
135: * @param argument
136: * The argument to pass to the constructor
137: * @return The new page
138: * @throws WicketRuntimeException
139: * Thrown if the Page cannot be instantiated using the given
140: * constructor and argument.
141: */
142: private final Page newPage(final Constructor constructor,
143: final Object argument) {
144: try {
145: return (Page) constructor
146: .newInstance(new Object[] { argument });
147: } catch (InstantiationException e) {
148: throw new WicketRuntimeException(
149: "Can't instantiate page using constructor "
150: + constructor + " and argument " + argument,
151: e);
152: } catch (IllegalAccessException e) {
153: throw new WicketRuntimeException(
154: "Can't instantiate page using constructor "
155: + constructor + " and argument " + argument,
156: e);
157: } catch (InvocationTargetException e) {
158: // honor redirect exception contract defined in IPageFactory
159: if (e.getTargetException() instanceof AbortException
160: || e.getTargetException() instanceof AuthorizationException
161: || e.getTargetException() instanceof MarkupException) {
162: throw (RuntimeException) e.getTargetException();
163: }
164: throw new WicketRuntimeException(
165: "Can't instantiate page using constructor "
166: + constructor + " and argument " + argument,
167: e);
168: }
169: }
170: }
|