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:
042: package org.netbeans.modules.web.jsf;
043:
044: import java.io.BufferedReader;
045: import java.io.BufferedWriter;
046: import java.io.File;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.io.InputStreamReader;
050: import java.io.OutputStreamWriter;
051: import java.math.BigInteger;
052: import java.net.URL;
053: import java.nio.charset.Charset;
054: import java.util.HashSet;
055: import java.util.List;
056: import java.util.Set;
057: import java.util.logging.Level;
058: import java.util.logging.Logger;
059: import org.netbeans.api.java.classpath.ClassPath;
060: import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
061: import org.netbeans.modules.j2ee.dd.api.common.InitParam;
062: import org.netbeans.modules.j2ee.dd.api.web.*;
063: import org.netbeans.modules.web.jsf.api.ConfigurationUtils;
064: import org.netbeans.modules.web.jsf.wizards.JSFConfigurationPanel;
065: import org.openide.DialogDescriptor;
066: import org.openide.filesystems.FileObject;
067: import org.openide.filesystems.FileSystem;
068: import org.openide.filesystems.FileUtil;
069: import org.openide.filesystems.FileLock;
070: import org.netbeans.api.project.libraries.Library;
071: import org.netbeans.api.project.libraries.LibraryManager;
072: import org.netbeans.api.queries.FileEncodingQuery;
073: import org.netbeans.modules.j2ee.common.Util;
074: import org.netbeans.modules.web.api.webmodule.ExtenderController;
075: import org.netbeans.modules.web.spi.webmodule.WebFrameworkProvider;
076: import org.netbeans.modules.web.api.webmodule.WebModule;
077: import org.netbeans.modules.web.spi.webmodule.WebModuleExtender;
078: import org.openide.util.NbBundle;
079:
080: /**
081: *
082: * @author Petr Pisl
083: */
084: public class JSFFrameworkProvider extends WebFrameworkProvider {
085:
086: private static final Logger LOGGER = Logger
087: .getLogger(JSFFrameworkProvider.class.getName());
088:
089: private static String WELCOME_JSF = "welcomeJSF.jsp"; //NOI18N
090: private static String FORWARD_JSF = "forwardToJSF.jsp"; //NOI18N
091: private static String RESOURCE_FOLDER = "org/netbeans/modules/web/jsf/resources/"; //NOI18N
092:
093: private JSFConfigurationPanel panel;
094:
095: /** Creates a new instance of JSFFrameworkProvider */
096: public JSFFrameworkProvider() {
097: super (NbBundle.getMessage(JSFFrameworkProvider.class,
098: "JSF_Name"), // NOI18N
099: NbBundle.getMessage(JSFFrameworkProvider.class,
100: "JSF_Description")); //NOI18N
101: }
102:
103: // not named extend() so as to avoid implementing WebFrameworkProvider.extend()
104: // better to move this to JSFConfigurationPanel
105: public Set extendImpl(WebModule webModule) {
106: Set result = new HashSet();
107: Library jsfLibrary = null;
108: Library jstlLibrary = null;
109:
110: JSFConfigurationPanel.LibraryType libraryType = panel
111: .getLibraryType();
112: if (libraryType == JSFConfigurationPanel.LibraryType.NEW) {
113: // create new jsf library
114: String libraryName = panel.getNewLibraryName();
115: File installFolder = panel.getInstallFolder();
116: if (installFolder != null && libraryName != null) {
117: try {
118: JSFUtils.createJSFUserLibrary(installFolder,
119: libraryName);
120: jsfLibrary = LibraryManager.getDefault()
121: .getLibrary(libraryName);
122: } catch (IOException exception) {
123: LOGGER
124: .log(
125: Level.WARNING,
126: "Exception during extending an web project",
127: exception); //NOI18N
128: }
129: }
130: } else {
131: if (libraryType == JSFConfigurationPanel.LibraryType.USED) {
132: //use a selected library
133: jsfLibrary = panel.getLibrary();
134: // if the selected library is a default one, add also JSTL library
135: if (jsfLibrary.getName().equals(
136: JSFUtils.DEFAULT_JSF_1_2_NAME)
137: || jsfLibrary.getName().equals(
138: JSFUtils.DEFAULT_JSF_1_1_NAME)) {
139: jstlLibrary = LibraryManager.getDefault()
140: .getLibrary(JSFUtils.DEFAULT_JSTL_1_1_NAME);
141: }
142: }
143: }
144:
145: try {
146: FileObject fileObject = webModule.getDocumentBase();
147: FileObject[] javaSources = webModule.getJavaSources();
148: if (jsfLibrary != null && javaSources.length > 0) {
149: Library[] libraries;
150: if (jstlLibrary != null) {
151: libraries = new Library[] { jsfLibrary, jstlLibrary };
152: } else {
153: libraries = new Library[] { jsfLibrary };
154: }
155: // This is a way how to add libraries to the project classpath and
156: // packed them to the war file by default.
157: ProjectClassPathModifier.addLibraries(libraries,
158: javaSources[0], ClassPath.COMPILE);
159: }
160:
161: boolean isMyFaces;
162: if (jsfLibrary != null) {
163: // find out whether the added library is myfaces jsf implementation
164: List<URL> content = jsfLibrary.getContent("classpath"); //NOI18N
165: isMyFaces = Util.containsClass(content,
166: JSFUtils.MYFACES_SPAECIFIC_CLASS);
167: } else {
168: // find out whether the target server has myfaces jsf implementation on the classpath
169: ClassPath cp = ClassPath.getClassPath(fileObject,
170: ClassPath.COMPILE);
171: isMyFaces = cp
172: .findResource(JSFUtils.MYFACES_SPAECIFIC_CLASS
173: .replace('.', '/')
174: + ".class") != null; //NOI18N
175: }
176:
177: FileSystem fileSystem = webModule.getWebInf()
178: .getFileSystem();
179: fileSystem.runAtomicAction(new CreateFacesConfig(webModule,
180: isMyFaces));
181: result.add(webModule.getDocumentBase().getFileObject(
182: "welcomeJSF", "jsp")); //NOI18N
183: } catch (IOException exception) {
184: LOGGER.log(Level.WARNING,
185: "Exception during extending an web project",
186: exception); //NOI18N
187: }
188: return result;
189: }
190:
191: public static String readResource(InputStream is, String encoding)
192: throws IOException {
193: // read the config from resource first
194: StringBuffer sbuffer = new StringBuffer();
195: String lineSep = System.getProperty("line.separator");//NOI18N
196: BufferedReader br = new BufferedReader(new InputStreamReader(
197: is, encoding));
198: String line = br.readLine();
199: while (line != null) {
200: sbuffer.append(line);
201: sbuffer.append(lineSep);
202: line = br.readLine();
203: }
204: br.close();
205: return sbuffer.toString();
206: }
207:
208: public java.io.File[] getConfigurationFiles(
209: org.netbeans.modules.web.api.webmodule.WebModule wm) {
210: // The JavaEE 5 introduce web modules without deployment descriptor. In such wm can not be jsf used.
211: FileObject dd = wm.getDeploymentDescriptor();
212: if (dd != null) {
213: FileObject[] filesFO = ConfigurationUtils
214: .getFacesConfigFiles(wm);
215: File[] files = new File[filesFO.length];
216: for (int i = 0; i < filesFO.length; i++)
217: files[i] = FileUtil.toFile(filesFO[i]);
218: if (files.length > 0)
219: return files;
220: }
221: return null;
222: }
223:
224: public WebModuleExtender createWebModuleExtender(
225: WebModule webModule, ExtenderController controller) {
226: boolean defaultValue = (webModule == null || !isInWebModule(webModule));
227: panel = new JSFConfigurationPanel(this , controller,
228: !defaultValue);
229: if (!defaultValue) {
230: // get configuration panel with values from the wm
231: Servlet servlet = ConfigurationUtils
232: .getFacesServlet(webModule);
233: panel.setServletName(servlet.getServletName());
234: panel.setURLPattern(ConfigurationUtils
235: .getFacesServletMapping(webModule));
236: panel.setValidateXML(JSFConfigUtilities
237: .validateXML(webModule.getDeploymentDescriptor()));
238: panel
239: .setVerifyObjects(JSFConfigUtilities
240: .verifyObjects(webModule
241: .getDeploymentDescriptor()));
242: }
243:
244: return panel;
245: }
246:
247: public boolean isInWebModule(
248: org.netbeans.modules.web.api.webmodule.WebModule webModule) {
249: // The JavaEE 5 introduce web modules without deployment descriptor. In such wm can not be jsf used.
250: FileObject dd = webModule.getDeploymentDescriptor();
251: return (dd != null && ConfigurationUtils
252: .getFacesServlet(webModule) != null);
253: }
254:
255: public String getServletPath(FileObject file) {
256: String url = null;
257: if (file == null)
258: return url;
259:
260: WebModule wm = WebModule.getWebModule(file);
261: if (wm != null) {
262: url = FileUtil.getRelativePath(wm.getDocumentBase(), file);
263: if (url.charAt(0) != '/')
264: url = "/" + url;
265: String mapping = ConfigurationUtils
266: .getFacesServletMapping(wm);
267: if (mapping != null && !"".equals(mapping)) {
268: if (mapping.endsWith("/*")) {
269: mapping = mapping
270: .substring(0, mapping.length() - 2);
271: url = mapping + url;
272: }
273: }
274: }
275: return url;
276: }
277:
278: public static void createFile(FileObject target, String content,
279: String encoding) throws IOException {
280: FileLock lock = target.lock();
281: try {
282: BufferedWriter bw = new BufferedWriter(
283: new OutputStreamWriter(
284: target.getOutputStream(lock), encoding));
285: bw.write(content);
286: bw.close();
287:
288: } finally {
289: lock.releaseLock();
290: }
291: }
292:
293: private class CreateFacesConfig implements FileSystem.AtomicAction {
294: private static final String FACES_SERVLET_CLASS = "javax.faces.webapp.FacesServlet"; //NOI18N
295: private static final String FACES_SERVLET_NAME = "Faces Servlet"; //NOI18N
296: private static final String FALSE = "false"; //NOI18N
297: private static final String INITPARAM_BEAN_NAME = "InitParam"; //NOI18N
298: private static final String MYFACES_STARTUP_LISTENER_CLASS = "org.apache.myfaces.webapp.StartupServletContextListener";//NOI18N
299: private static final String SAVINGMETHOD_PARAM_NAME = "javax.faces.STATE_SAVING_METHOD";//NOI18N
300: private static final String TRUE = "true"; //NOI18N
301: private static final String VALIDATEXML_PARAM_NAME = "com.sun.faces.validateXml"; //NOI18N
302: private static final String VERIFYOBJECTS_PARAM_NAME = "com.sun.faces.verifyObjects"; //NOI18N
303: WebModule webModule;
304: boolean isMyFaces;
305:
306: public CreateFacesConfig(WebModule webModule, boolean isMyFaces) {
307: this .webModule = webModule;
308: this .isMyFaces = isMyFaces;
309: }
310:
311: public void run() throws IOException {
312: // Enter servlet into the deployment descriptor
313: FileObject dd = webModule.getDeploymentDescriptor();
314: //faces servlet mapping
315: String facesMapping = panel == null ? "faces/*" : panel
316: .getURLPattern();
317:
318: WebApp ddRoot = DDProvider.getDefault().getDDRoot(dd);
319: if (ddRoot != null) {
320: try {
321: boolean servletDefined = false;
322: Servlet servlet;
323: Servlet[] servlets = ddRoot.getServlet();
324: for (int i = 0; i < servlets.length; i++) {
325: servlet = servlets[i];
326: if (FACES_SERVLET_CLASS.equals(servlet
327: .getServletClass().trim())) {
328: servletDefined = true;
329: break;
330: }
331: }
332:
333: if (!servletDefined) {
334: servlet = (Servlet) ddRoot
335: .createBean("Servlet"); //NOI18N
336: String servletName = panel == null ? FACES_SERVLET_NAME
337: : panel.getServletName();
338: servlet.setServletName(servletName);
339: servlet.setServletClass(FACES_SERVLET_CLASS);
340: servlet.setLoadOnStartup(new BigInteger("1"));//NOI18N
341: ddRoot.addServlet(servlet);
342:
343: ServletMapping mapping = (ServletMapping) ddRoot
344: .createBean("ServletMapping"); //NOI18N
345: mapping.setServletName(servletName);//NOI18N
346: mapping
347: .setUrlPattern(panel == null ? "/faces/*"
348: : panel.getURLPattern());//NOI18N
349:
350: ddRoot.addServletMapping(mapping);
351: }
352:
353: boolean verifyObjectsDefined = false;
354: boolean validateXmlDefined = false;
355: boolean savingMethodDefined = false;
356:
357: InitParam[] params = ddRoot.getContextParam();
358: for (int i = 0; i < params.length
359: && !(verifyObjectsDefined
360: && validateXmlDefined && savingMethodDefined); i++) {
361: InitParam initParam = params[i];
362: String name = initParam.getParamName().trim();
363: if (VERIFYOBJECTS_PARAM_NAME.equals(name)) {
364: verifyObjectsDefined = true;
365: } else if (VALIDATEXML_PARAM_NAME.equals(name)) {
366: validateXmlDefined = true;
367: } else if (SAVINGMETHOD_PARAM_NAME.equals(name)) {
368: savingMethodDefined = true;
369: }
370: }
371:
372: InitParam contextParam;
373: if (!verifyObjectsDefined) {
374: contextParam = (InitParam) ddRoot
375: .createBean(INITPARAM_BEAN_NAME);
376: contextParam
377: .setParamName(VERIFYOBJECTS_PARAM_NAME);
378: if (panel != null && panel.verifyObjects())
379: contextParam.setParamValue(TRUE);
380: else
381: contextParam.setParamValue(FALSE);
382: ddRoot.addContextParam(contextParam);
383: }
384:
385: if (!validateXmlDefined) {
386: contextParam = (InitParam) ddRoot
387: .createBean(INITPARAM_BEAN_NAME);
388: contextParam
389: .setParamName(VALIDATEXML_PARAM_NAME);
390: if (panel == null || panel.validateXML())
391: contextParam.setParamValue(TRUE);
392: else
393: contextParam.setParamValue(FALSE);
394: ddRoot.addContextParam(contextParam);
395: }
396:
397: if (!savingMethodDefined) {
398: contextParam = (InitParam) ddRoot
399: .createBean(INITPARAM_BEAN_NAME);
400: contextParam
401: .setParamName(SAVINGMETHOD_PARAM_NAME);
402: contextParam.setParamValue("client");
403: ddRoot.addContextParam(contextParam);
404: }
405:
406: if (isMyFaces) {
407: boolean listenerDefined = false;
408: Listener listeners[] = ddRoot.getListener();
409: for (int i = 0; i < listeners.length; i++) {
410: if (MYFACES_STARTUP_LISTENER_CLASS
411: .equals(listeners[i]
412: .getListenerClass().trim())) {
413: listenerDefined = true;
414: break;
415: }
416: }
417: if (!listenerDefined) {
418: Listener facesListener = (Listener) ddRoot
419: .createBean("Listener"); //NOI18N
420: facesListener
421: .setListenerClass(MYFACES_STARTUP_LISTENER_CLASS);
422: ddRoot.addListener(facesListener);
423: }
424: }
425: // add welcome file
426: WelcomeFileList welcomeFiles = ddRoot
427: .getSingleWelcomeFileList();
428: if (welcomeFiles == null) {
429: welcomeFiles = (WelcomeFileList) ddRoot
430: .createBean("WelcomeFileList"); //NOI18N
431: ddRoot.setWelcomeFileList(welcomeFiles);
432: }
433: // add the welcome file only if there not any
434: if (welcomeFiles.sizeWelcomeFile() == 0) {
435: if (facesMapping.charAt(0) == '/') {
436: // if the mapping start with '/' (like /faces/*), then the welcame file can be the mapping
437: welcomeFiles
438: .addWelcomeFile(ConfigurationUtils
439: .translateURI(facesMapping,
440: WELCOME_JSF));
441: } else {
442: // if the mapping doesn't strat '/' (like *.jsf), then the welcome file has to be
443: // a helper file, which will foward the request to the right url
444: welcomeFiles.addWelcomeFile(FORWARD_JSF);
445: //copy forwardToJSF.jsp
446: if (facesMapping.charAt(0) != '/'
447: && canCreateNewFile(webModule
448: .getDocumentBase(),
449: FORWARD_JSF)) { //NOI18N
450: String content = readResource(Thread
451: .currentThread()
452: .getContextClassLoader()
453: .getResourceAsStream(
454: RESOURCE_FOLDER
455: + FORWARD_JSF),
456: "UTF-8"); //NOI18N
457: content = content.replace(
458: "__FORWARD__",
459: ConfigurationUtils
460: .translateURI(
461: facesMapping,
462: WELCOME_JSF));
463: Charset encoding = FileEncodingQuery
464: .getDefaultEncoding();
465: content = content
466: .replaceAll("__ENCODING__",
467: encoding.name());
468: FileObject target = FileUtil
469: .createData(webModule
470: .getDocumentBase(),
471: FORWARD_JSF);//NOI18N
472: createFile(target, content, encoding
473: .name()); //NOI18N
474: }
475: }
476: }
477: ddRoot.write(dd);
478:
479: } catch (ClassNotFoundException cnfe) {
480: LOGGER.log(Level.WARNING,
481: "Exception in JSFMoveClassPlugin", cnfe); //NOI18N
482: }
483: }
484:
485: // copy faces-config.xml
486: if (canCreateNewFile(webModule.getWebInf(),
487: "faces-config.xml")) { //NO18N
488: String facesConfigTemplate = "faces-config.xml"; //NOI18N
489: if (ddRoot != null) {
490: if (WebApp.VERSION_2_5.equals(ddRoot.getVersion())) {
491: facesConfigTemplate = "faces-config_1_2.xml"; //NOI18N
492: }
493: }
494: String content = readResource(Thread.currentThread()
495: .getContextClassLoader().getResourceAsStream(
496: RESOURCE_FOLDER + facesConfigTemplate),
497: "UTF-8"); //NOI18N
498: FileObject target = FileUtil.createData(webModule
499: .getWebInf(), "faces-config.xml");//NOI18N
500: createFile(target, content, "UTF-8"); //NOI18N
501: }
502:
503: //copy Welcome.jsp
504:
505: if (canCreateNewFile(webModule.getDocumentBase(),
506: WELCOME_JSF)) {
507: String content = readResource(Thread.currentThread()
508: .getContextClassLoader().getResourceAsStream(
509: RESOURCE_FOLDER + WELCOME_JSF), "UTF-8"); //NOI18N
510: Charset encoding = FileEncodingQuery
511: .getDefaultEncoding();
512: content = content.replaceAll("__ENCODING__", encoding
513: .name());
514: FileObject target = FileUtil.createData(webModule
515: .getDocumentBase(), WELCOME_JSF);//NOI18N
516: createFile(target, content, encoding.name()); //NOI18N
517: }
518: }
519:
520: private boolean canCreateNewFile(FileObject parent, String name) {
521: File fileToBe = new File(FileUtil.toFile(parent), name);
522: boolean create = true;
523: if (fileToBe.exists()) {
524: DialogDescriptor dialog = new DialogDescriptor(NbBundle
525: .getMessage(JSFFrameworkProvider.class,
526: "MSG_OverwriteFile", fileToBe
527: .getAbsolutePath()), NbBundle
528: .getMessage(JSFFrameworkProvider.class,
529: "TTL_OverwriteFile"), true,
530: DialogDescriptor.YES_NO_OPTION,
531: DialogDescriptor.NO_OPTION, null);
532: java.awt.Dialog d = org.openide.DialogDisplayer
533: .getDefault().createDialog(dialog);
534: d.setVisible(true);
535: create = (dialog.getValue() == org.openide.DialogDescriptor.NO_OPTION);
536: }
537: return create;
538: }
539: }
540: }
|