001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.util.Hashtable;
009: import java.util.Map;
010:
011: import org.apache.commons.logging.Log;
012: import org.apache.commons.logging.LogFactory;
013: import org.jasig.portal.car.CarResources;
014: import org.jasig.portal.layout.IUserLayoutManager;
015: import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
016:
017: /**
018: * A factory class that produces <code>IChannel</code> instances.
019: * This class maintains a lazily-loaded, but permanent
020: * cache of channels that implement one of uPortal's
021: * multithreaded interfaces, IMultithreadedChannel or one of its variants.
022: *
023: * @author <a href="mailto:pkharchenko@unicon.net">Peter Kharchenko</a>
024: * @version $Revision: 36378 $
025: */
026: public class ChannelFactory {
027:
028: private static final Log log = LogFactory
029: .getLog(ChannelFactory.class);
030:
031: /** table of multithreaded channels */
032: private static final Hashtable staticChannels = new Hashtable();
033:
034: /** Create a CAR class loader object for loading channel classes from CARs
035: * Note that the current class loader is passed as the parent and is
036: * searched before CARs are. So if a class exists in the VM classpath
037: * _and_ in a CAR the one on the classpath will be found first.
038: */
039: private static ClassLoader classLoader = CarResources.getInstance()
040: .getClassLoader();
041:
042: /**
043: * Instantiate a channel from information supplied by the user layout manager.
044: *
045: * @param channelSubscribeId a <code>String</code> value
046: * @param ulm an <code>IUserLayoutManager</code> value
047: * @param sessionId a <code>String</code> HTTP session Id value
048: * @return an <code>IChannel</code> instance
049: * @exception PortalException if an error occurs
050: */
051: public static IChannel instantiateLayoutChannel(
052: String channelSubscribeId, IUserLayoutManager ulm,
053: String sessionId) throws PortalException {
054: // get channel information from the user layout manager
055: IUserLayoutChannelDescription channel = (IUserLayoutChannelDescription) ulm
056: .getNode(channelSubscribeId);
057: if (channel != null) {
058: String className = channel.getClassName();
059: String channelPublishId = channel.getChannelPublishId();
060: long timeOut = channel.getTimeout();
061: try {
062: return instantiateChannel(channelSubscribeId,
063: channelPublishId, className, timeOut, channel
064: .getParameterMap(), sessionId);
065: } catch (Exception ex) {
066: log
067: .error("ChannelManager::instantiateChannel() : unable to instantiate channel class \""
068: + className + "\". " + ex);
069: return null;
070: }
071: } else
072: return null;
073: }
074:
075: /**
076: * Construct channel instance based on a channel description object.
077: *
078: * @param description an <code>IUserLayoutChannelDescription</code> value
079: * @param sessionId a <code>String</code> HTTP session Id value
080: * @return an <code>IChannel</code> value
081: */
082: public static IChannel instantiateLayoutChannel(
083: IUserLayoutChannelDescription description, String sessionId)
084: throws PortalException {
085: return instantiateChannel(description.getChannelSubscribeId(),
086: description.getChannelPublishId(), description
087: .getClassName(), description.getTimeout(),
088: description.getParameterMap(), sessionId);
089: }
090:
091: private static IChannel instantiateChannel(
092: String channelSubscribeId, String channelPublishId,
093: String className, long timeOut, Map params, String sessionId)
094: throws PortalException {
095: String uid = sessionId + "/" + channelSubscribeId;
096: return instantiateChannel(className, uid);
097: }
098:
099: /**
100: * Produce an IChannel based on a java class name. If the java class
101: * specified implements a channel interface other than
102: * <code>org.jasig.portal.IChannel</code>, it will be wrapped by an
103: * appropriate adapter class that does implement IChannel.
104: * @param className the channel's java class name
105: * @param uid a unique ID for use with multithreaded channels
106: * @return an <code>IChannel</code> object
107: */
108: public static IChannel instantiateChannel(String className,
109: String uid) throws PortalException {
110: IChannel ch = null;
111:
112: Class channelClass = null;
113:
114: Object cobj = null;
115: try {
116: // Load the class using the CAR class loader which uses
117: // the default class loader before looking into the CARs
118: channelClass = classLoader.loadClass(className);
119: } catch (Exception e) {
120: throw new PortalException("Unable to load class '"
121: + className + "'", e);
122: }
123:
124: // if this channel is neither an IMultithreadedCharacterChannel nor an
125: // IMultithreadedChannel
126: if (!IMultithreadedCharacterChannel.class
127: .isAssignableFrom(channelClass)
128: && !IMultithreadedChannel.class
129: .isAssignableFrom(channelClass)) {
130:
131: // then we can go ahead and instantiate it
132: try {
133: cobj = channelClass.newInstance();
134: return (IChannel) cobj;
135: } catch (Throwable t) {
136: throw new PortalException(
137: "Unable to instantiate class '" + className
138: + "'", t);
139: }
140: // note that no synchronization is required to service IChannel instantiation
141: } else {
142:
143: // synchronizing is required to honor IMultithreaded's single-instantiation
144: // guarantee
145:
146: synchronized (ChannelFactory.class) {
147: // Avoid instantiating a multithreaded channel more than once
148: // by storing it in a staticChannels table.
149: cobj = staticChannels.get(className);
150: if (cobj == null) {
151: try {
152: cobj = channelClass.newInstance();
153: staticChannels.put(className, cobj);
154: } catch (Throwable t) {
155: throw new PortalException(
156: "Unable to instantiate class '"
157: + className + "'", t);
158: }
159: }
160: }
161:
162: // determine what kind of a channel it is.
163: if (cobj instanceof IMultithreadedCharacterChannel) {
164: if (cobj instanceof IMultithreadedCacheable) {
165: if (cobj instanceof IMultithreadedPrivileged) {
166: if (cobj instanceof IMultithreadedMimeResponse) {
167: ch = new MultithreadedPrivilegedCacheableMimeResponseCharacterChannelAdapter(
168: (IMultithreadedCharacterChannel) cobj,
169: uid);
170: } else if (cobj instanceof IMultithreadedDirectResponse) {
171: // cacheable, privileged and direct response
172: ch = new MultithreadedPrivilegedCacheableDirectResponseCharacterChannelAdapter(
173: (IMultithreadedCharacterChannel) cobj,
174: uid);
175: } else {
176: // both cacheable and privileged
177: ch = new MultithreadedPrivilegedCacheableCharacterChannelAdapter(
178: (IMultithreadedCharacterChannel) cobj,
179: uid);
180: }
181: } else {
182: if (cobj instanceof IMultithreadedMimeResponse) {
183: ch = new MultithreadedCacheableMimeResponseCharacterChannelAdapter(
184: (IMultithreadedCharacterChannel) cobj,
185: uid);
186: } else {
187: // just cacheable
188: ch = new MultithreadedCacheableCharacterChannelAdapter(
189: (IMultithreadedCharacterChannel) cobj,
190: uid);
191: }
192: }
193: } else if (cobj instanceof IMultithreadedPrivileged) {
194: if (cobj instanceof IMultithreadedMimeResponse) {
195: ch = new MultithreadedPrivilegedMimeResponseCharacterChannelAdapter(
196: (IMultithreadedCharacterChannel) cobj,
197: uid);
198: } else {
199: ch = new MultithreadedPrivilegedCharacterChannelAdapter(
200: (IMultithreadedCharacterChannel) cobj,
201: uid);
202: }
203: } else {
204: if (cobj instanceof IMultithreadedMimeResponse) {
205: ch = new MultithreadedMimeResponseCharacterChannelAdapter(
206: (IMultithreadedCharacterChannel) cobj,
207: uid);
208: } else {
209: // plain multithreaded
210: ch = new MultithreadedCharacterChannelAdapter(
211: (IMultithreadedCharacterChannel) cobj,
212: uid);
213: }
214: }
215: } else if (cobj instanceof IMultithreadedChannel) {
216: if (cobj instanceof IMultithreadedCacheable) {
217: if (cobj instanceof IMultithreadedPrivileged) {
218: if (cobj instanceof IMultithreadedMimeResponse) {
219: ch = new MultithreadedPrivilegedCacheableMimeResponseChannelAdapter(
220: (IMultithreadedChannel) cobj, uid);
221: } else {
222: // both cacheable and privileged
223: ch = new MultithreadedPrivilegedCacheableChannelAdapter(
224: (IMultithreadedChannel) cobj, uid);
225: }
226: } else {
227: if (cobj instanceof IMultithreadedMimeResponse) {
228: ch = new MultithreadedCacheableMimeResponseChannelAdapter(
229: (IMultithreadedChannel) cobj, uid);
230: } else {
231: // just cacheable
232: ch = new MultithreadedCacheableChannelAdapter(
233: (IMultithreadedChannel) cobj, uid);
234: }
235: }
236: } else if (cobj instanceof IMultithreadedPrivileged) {
237: if (cobj instanceof IMultithreadedMimeResponse) {
238: ch = new MultithreadedPrivilegedMimeResponseChannelAdapter(
239: (IMultithreadedChannel) cobj, uid);
240: } else {
241: ch = new MultithreadedPrivilegedChannelAdapter(
242: (IMultithreadedChannel) cobj, uid);
243: }
244: } else {
245: if (cobj instanceof IMultithreadedMimeResponse) {
246: ch = new MultithreadedMimeResponseChannelAdapter(
247: (IMultithreadedChannel) cobj, uid);
248: } else {
249: // plain multithreaded
250: ch = new MultithreadedChannelAdapter(
251: (IMultithreadedChannel) cobj, uid);
252: }
253: }
254: } else {
255: throw new IllegalStateException(
256: "Channel object must either implement IMultithreadedChannel or IMultithreadedChannel for control to get here.");
257: }
258: }
259: return ch;
260: }
261: }
|