001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.jsfsupport.container;
042:
043: import com.sun.faces.RIConstants;
044: import java.lang.reflect.Field;
045: import java.util.ArrayList;
046: import java.util.HashMap;
047: import java.util.Iterator;
048:
049: import javax.faces.FactoryFinder;
050: import javax.faces.application.Application;
051: import javax.faces.application.ApplicationFactory;
052: import javax.faces.application.FacesMessage;
053: import javax.faces.application.FacesMessage.Severity;
054: import javax.faces.component.UIViewRoot;
055: import javax.faces.context.ExternalContext;
056: import javax.faces.context.FacesContext;
057: import javax.faces.context.ResponseStream;
058: import javax.faces.context.ResponseWriter;
059: import javax.faces.el.PropertyResolver;
060: import javax.faces.render.RenderKit;
061:
062: //import com.sun.rave.web.ui.faces.DataProviderPropertyResolver;
063: import com.sun.rave.designtime.DesignContext;
064:
065: //import com.sun.jsfcl.data.ResultSetPropertyResolver;
066: import com.sun.faces.application.ApplicationAssociate;
067: import com.sun.faces.application.ApplicationImpl;
068: import com.sun.faces.config.ConfigureListener;
069: import com.sun.faces.el.ELContextImpl;
070: import javax.el.ELContext;
071: import javax.faces.render.RenderKitFactory;
072: import javax.servlet.ServletContext;
073: import org.openide.ErrorManager;
074:
075: /**
076: * RaveFacesContext provides a JSF context for design-time use
077: *
078: * @author Robert Brewin
079: * @author Winston Prakash - Modifications to support JSF 1.2
080: * @version 1.0
081: */
082: public class RaveFacesContext extends FacesContext {
083:
084: private static final String FACESCONTEXT_IMPL_ATTR_NAME = RIConstants.FACES_PREFIX
085: + "FacesContextImpl";
086:
087: private ELContext elContext = null;
088:
089: /**
090: * The view root used for a given context
091: */
092: private UIViewRoot viewRoot;
093:
094: /**
095: * The stream to use for emitting renderered output
096: */
097: private ResponseStream responseStream;
098:
099: /**
100: * The writer used for emitting output
101: */
102: private ResponseWriter responseWriter;
103:
104: /**
105: * The "external" context for this faces container
106: */
107: private ExternalContext externalContext;
108:
109: /**
110: * The live context for this faces container
111: */
112: private DesignContext liveContext;
113:
114: /**
115: * The application for this faces container, cached from factory
116: */
117: private Application application;
118:
119: /**
120: * A hash of ArrayLists of Messages
121: * key: clientId
122: * value: an arraylist of messages assoc. with clientId
123: */
124: private HashMap messageHash;
125:
126: /**
127: * maxServerity
128: * the highest serverity of any message in messageHash
129: */
130: private Severity maxSeverity;
131:
132: private boolean released;
133: private RenderKitFactory rkFactory;
134: private RenderKit lastRk;
135: private String lastRkId;
136:
137: private ServletContext servletContext;
138:
139: /**
140: * <p>Parameter signature for the constructor of a PropertyResolver
141: * that takes a PropertyResolver argument.</p>
142: */
143: private Class signature[] = new Class[] { PropertyResolver.class };
144:
145: /**
146: * Constructor for this faces context, initialized with an external context
147: *
148: * @param context -- the context to use
149: */
150: public RaveFacesContext(ExternalContext context) {
151: setCurrentInstance(this );
152: externalContext = context;
153: messageHash = new HashMap();
154: maxSeverity = null;
155: // Store this in request scope so jsf-api can access it.
156:
157: this .externalContext.getRequestMap().put(
158: FACESCONTEXT_IMPL_ATTR_NAME, this );
159: rkFactory = (RenderKitFactory) FactoryFinder
160: .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
161: }
162:
163: public void unsetCurrentInstance() {
164: setCurrentInstance(null);
165: }
166:
167: public void setCurrentInstance() {
168: setCurrentInstance(this );
169: } // ---------------------------------------------------------------------------------- Properties
170:
171: public void setServletContext(ServletContext context) {
172: servletContext = context;
173: }
174:
175: /**
176: * <p>Reset the <code>Application</code> instance returned by
177: * <code>ApplicationFactory</code> to a pristine instance, and
178: * release our cached reference so that the next call to
179: * <code>getApplication()</code> will get a new one.</p>
180: */
181: public void resetApplication() {
182: try {
183:
184: setCurrentInstance(this );
185:
186: // This hack is to fix the bug NPE from com.sun.faces.spi.InjectionProviderFactory.findProviderClass()
187: // Once we set the ThreadLocal<ExternalContext>, it is being looked for instance of WebConfiguration
188: // So get the one from Servlet context and set to it.
189: getExternalContext()
190: .getApplicationMap()
191: .put(
192: "com.sun.faces.config.WebConfiguration",
193: servletContext
194: .getAttribute("com.sun.faces.config.WebConfiguration"));
195:
196: // Also nuke the old Application Associate from the map or it will complain
197: ApplicationAssociate.clearInstance(getExternalContext());
198:
199: // Reset the instance to be returned by ApplicationFactory
200: ApplicationFactory appFactory = (ApplicationFactory) FactoryFinder
201: .getFactory(FactoryFinder.APPLICATION_FACTORY);
202:
203: if (appFactory == null) {
204: throw new IllegalStateException("ApplicationFactory"); // NOI18N
205: }
206:
207: appFactory.setApplication(new ApplicationImpl());
208:
209: // Clear our cached reference (if any)
210: application = null;
211: } catch (Throwable t) {
212: org.openide.ErrorManager.getDefault().notify(t);
213: }
214: }
215:
216: private static ThreadLocal getConfigureListenerThreadLocalExternalContext() {
217: try {
218: Field field = ConfigureListener.class
219: .getDeclaredField("tlsExternalContext"); // NOI18N
220: field.setAccessible(true);
221: Object result;
222: result = field.get(null);
223: return result instanceof ThreadLocal ? (ThreadLocal) result
224: : null;
225: } catch (SecurityException se) {
226: ErrorManager.getDefault().notify(
227: ErrorManager.INFORMATIONAL, se);
228: } catch (NoSuchFieldException nfe) {
229: ErrorManager.getDefault().notify(
230: ErrorManager.INFORMATIONAL, nfe);
231: } catch (IllegalArgumentException iae) {
232: ErrorManager.getDefault().notify(
233: ErrorManager.INFORMATIONAL, iae);
234: } catch (IllegalAccessException iace) {
235: ErrorManager.getDefault().notify(
236: ErrorManager.INFORMATIONAL, iace);
237: }
238:
239: return null;
240: }
241:
242: /**
243: * <p>Return the {@link javax.faces.application.Application} instance associated with this
244: * web application.</p>
245: */
246: public Application getApplication() {
247:
248: // Return any previously cached application instance
249: if (application != null) {
250: return application;
251: }
252:
253: // Acquire a reference to the Application instance for this application
254: ApplicationFactory appFactory = (ApplicationFactory) FactoryFinder
255: .getFactory(FactoryFinder.APPLICATION_FACTORY);
256: if (appFactory == null) {
257: throw new IllegalStateException("ApplicationFactory"); // NOI18N
258: }
259: application = appFactory.getApplication();
260: if (application == null) {
261: throw new IllegalStateException("Application"); // NOI18N
262: }
263:
264: // Return our configured instance
265: return application;
266: }
267:
268: public ELContext getELContext() {
269: assertNotReleased();
270: if (elContext == null) {
271: elContext = new ELContextImpl(getApplication()
272: .getELResolver());
273: elContext.putContext(FacesContext.class, this );
274: UIViewRoot root = this .getViewRoot();
275: if (null != root) {
276: elContext.setLocale(root.getLocale());
277: }
278: }
279: return elContext;
280: }
281:
282: private void assertNotReleased() {
283: if (released) {
284: throw new IllegalStateException();
285: }
286: }
287:
288: /**
289: * Return the external context
290: */
291: public Iterator getClientIdsWithMessages() {
292: return messageHash.keySet().iterator();
293: }
294:
295: /**
296: * Return the external context
297: * @return the <code>ExternalContext</code> associated with this faces context
298: */
299: public ExternalContext getExternalContext() {
300: return externalContext;
301: }
302:
303: /**
304: * Return the current DesignContext
305: * @return the <code>DesignContext</code> associated with this faces context
306: */
307: public DesignContext getDesignContext() {
308: return liveContext;
309: }
310:
311: /**
312: * Set the current DesignContext
313: * @param liveContext
314: */
315: public void setDesignContext(DesignContext liveContext) {
316: this .liveContext = liveContext;
317: }
318:
319: /**
320: *
321: */
322: public Severity getMaximumSeverity() {
323: return maxSeverity;
324: }
325:
326: /**
327: *
328: */
329: public Iterator getMessages() {
330: ArrayList messages = new ArrayList();
331: messages.add(new FacesMessage(FacesMessage.SEVERITY_ERROR,
332: "msg-summary", "msg-detail"));
333: return messages.iterator();
334: /*
335: ArrayList allMessages = new ArrayList();
336: Iterator iter = messageHash.values().iterator();
337: while (iter.hasNext()) {
338: ArrayList messages = (ArrayList)iter.next();
339: Iterator messageIter = messages.iterator();
340: while (messageIter.hasNext()) {
341: allMessages.add(messageIter.next());
342: }
343: }
344: return allMessages.iterator();
345: */
346: }
347:
348: /**
349: *
350: */
351: public Iterator getMessages(String clientId) {
352: ArrayList messages = new ArrayList();
353: messages.add(new FacesMessage(FacesMessage.SEVERITY_ERROR,
354: "msg-summary", "msg-detail"));
355: return messages.iterator();
356: /*
357: ArrayList messages = (ArrayList)messageHash.get(clientId);
358: if (messages == null) {
359: messages = new ArrayList();
360: }
361: return messages.iterator();
362: */
363: }
364:
365: /**
366: * <p>Return the {@link RenderKit} instance for the render kit identifier
367: * specified on our {@link UIViewRoot}, if there is one.
368: */
369: public RenderKit getRenderKit() {
370: assertNotReleased();
371: UIViewRoot vr = getViewRoot();
372: if (vr == null) {
373: return (null);
374: }
375: String renderKitId = vr.getRenderKitId();
376:
377: if (renderKitId.equals(lastRkId)) {
378: return lastRk;
379: } else {
380: lastRk = rkFactory.getRenderKit(this , renderKitId);
381: lastRkId = renderKitId;
382: return lastRk;
383: }
384: }
385:
386: /**
387: * <p>Return <code>true</code> if the <code>renderResponse()</code>
388: * method has been called for the current request.</p>
389: */
390: public boolean getRenderResponse() {
391: // TODO: Make this functional if needed
392: return false;
393: }
394:
395: /**
396: * <p>Return <code>true</code> if the <code>responseComplete()</code>
397: * method has been called for the current request.</p>
398: */
399: public boolean getResponseComplete() {
400: // TODO: Make this functional if needed
401: return false;
402: }
403:
404: /**
405: *
406: */
407: public ResponseStream getResponseStream() {
408: return responseStream;
409: }
410:
411: /**
412: *
413: */
414: public void setResponseStream(ResponseStream responseStream) {
415: this .responseStream = responseStream;
416: }
417:
418: /**
419: *
420: */
421: public ResponseWriter getResponseWriter() {
422: return responseWriter;
423: }
424:
425: /**
426: *
427: */
428: public void setResponseWriter(ResponseWriter responseWriter) {
429: this .responseWriter = responseWriter;
430: }
431:
432: /**
433: * <p>Return the component view that is associated with the this request.
434: * </p>
435: */
436: public UIViewRoot getViewRoot() {
437: return this .viewRoot;
438: }
439:
440: /**
441: *
442: */
443: public void setViewRoot(UIViewRoot viewRoot) {
444: if (viewRoot == null) {
445: // TODO: Make this functional if needed
446: }
447: this .viewRoot = viewRoot;
448: }
449:
450: // ------------------------------------------------------------------------------ Public Methods
451:
452: /**
453: *
454: */
455: public void addMessage(String clientId, FacesMessage message) {
456: ArrayList messages = (ArrayList) messageHash.get(clientId);
457: if (messages == null) {
458: messages = new ArrayList();
459: messageHash.put(clientId, messages);
460: }
461: messages.add(message);
462: if (maxSeverity == null) {
463: maxSeverity = message.getSeverity();
464: } else if (message.getSeverity().getOrdinal() > maxSeverity
465: .getOrdinal()) {
466: maxSeverity = message.getSeverity();
467: }
468: }
469:
470: /**
471: *
472: */
473: public void release() {
474: // TODO: other stuff?
475: messageHash = new HashMap();
476: maxSeverity = null;
477:
478: this .externalContext.getRequestMap().remove(
479: FACESCONTEXT_IMPL_ATTR_NAME);
480:
481: released = true;
482: externalContext = null;
483: responseStream = null;
484: responseWriter = null;
485: //componentMessageLists = null;
486: //renderResponse = false;
487: //responseComplete = false;
488: viewRoot = null;
489:
490: // PENDING(edburns): write testcase that verifies that release
491: // actually works. This will be important to keep working as
492: // ivars are added and removed on this class over time.
493:
494: // Make sure to clear our ThreadLocal instance.
495: setCurrentInstance(null);
496: }
497:
498: /**
499: *
500: */
501: public void renderResponse() {
502: // TODO: Make this functional if needed
503: }
504:
505: /**
506: *
507: */
508: public void responseComplete() {
509: // TODO: Make this functional if needed
510: }
511:
512: }
|