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