001: /*
002: * To change this template, choose Tools | Templates | Licenses | Default License
003: * and open the template in the editor.
004: */
005: package org.netbeans.modules.visualweb.jsfsupport.container;
006:
007: import java.io.ByteArrayInputStream;
008: import java.io.IOException;
009: import java.net.URL;
010: import java.util.ArrayList;
011: import java.util.Enumeration;
012: import java.util.HashMap;
013: import java.util.List;
014: import java.util.Map;
015: import java.util.zip.ZipEntry;
016: import java.util.zip.ZipFile;
017: import javax.faces.webapp.UIComponentTagBase;
018: import javax.xml.parsers.DocumentBuilder;
019: import javax.xml.parsers.DocumentBuilderFactory;
020: import javax.xml.parsers.ParserConfigurationException;
021: import org.openide.filesystems.FileObject;
022: import org.openide.filesystems.FileUtil;
023: import org.openide.filesystems.URLMapper;
024: import org.openide.util.Exceptions;
025: import org.openide.util.NbBundle;
026: import org.w3c.dom.Document;
027: import org.w3c.dom.Element;
028: import org.w3c.dom.Node;
029: import org.w3c.dom.NodeList;
030: import org.xml.sax.EntityResolver;
031: import org.xml.sax.InputSource;
032: import org.xml.sax.SAXException;
033:
034: /**
035: * A Support class to find the JSF component corresponding to the JSP tag and TagLib URI
036: * @author Winston Prakash
037: */
038: public class JsfTagSupport {
039:
040: private Map<String, TagInfo> tagInfoMap = new HashMap<String, TagInfo>();
041: private Map<String, ComponentInfo> componentInfoMap = new HashMap<String, ComponentInfo>();
042: // Static map of Taglib URI and taglib and faces-config locations in a jar
043: private static Map<String, TagLibFacesConfigInfo> statictTaglibFacesConfigLocationMap = new HashMap<String, TagLibFacesConfigInfo>();
044: // Cache of Taglib URI and JSF tag support
045: private static Map<String, JsfTagSupport> cachedTagLibraryInfoMap = new HashMap<String, JsfTagSupport>();
046: private static Object lock = new Object();
047:
048: /**
049: * This method should be called only once when the designtime JSF container is initialzed,
050: * passing the project classloader. The classpath (jars) of the classloader is scanned for
051: * TLD files and faces config files. Their locations are cached for later use
052: * @param classLoader
053: */
054: public static synchronized void initialize(ClassLoader classLoader) {
055: try {
056: Enumeration<URL> urls = classLoader
057: .getResources("META-INF/faces-config.xml");
058: while (urls.hasMoreElements()) {
059: URL url = urls.nextElement();
060: if (!url.getPath().contains("jsfcl.jar")) {
061: addTaglibFacesConfigMapEntry(url);
062: }
063: }
064:
065: // Bug Fix 124610 - Unfortunately the JSF RI component informations are not kept
066: // in the standard location (META-INF/faces-config.xml)
067: URL facesConfigUrl = classLoader
068: .getResource("com/sun/faces/jsf-ri-runtime.xml");
069: URL tagLibUrl = new URL(facesConfigUrl.toString()
070: .split("!")[0]
071: + "!/META-INF/html_basic.tld");
072: String taglibUri = "http://java.sun.com/jsf/html";
073: TagLibFacesConfigInfo tagLibFacesConfigInfo = new TagLibFacesConfigInfo(
074: taglibUri);
075: tagLibFacesConfigInfo.addTagLibUrl(tagLibUrl);
076: tagLibFacesConfigInfo.addFacesConfigUrl(facesConfigUrl);
077: statictTaglibFacesConfigLocationMap.put(taglibUri,
078: tagLibFacesConfigInfo);
079: } catch (Exception ex) {
080: Exceptions.printStackTrace(ex);
081: }
082: }
083:
084: private static void addTaglibFacesConfigMapEntry(URL facesConfigUrl)
085: throws IOException, ParserConfigurationException,
086: SAXException {
087: FileObject facesConfigFileObject = URLMapper
088: .findFileObject(facesConfigUrl);
089: String zipFilePath = FileUtil.toFile(
090: FileUtil.getArchiveFile(facesConfigFileObject))
091: .getAbsolutePath();
092: ZipFile in = new ZipFile(zipFilePath);
093: Enumeration<? extends ZipEntry> entries = in.entries();
094: while (entries.hasMoreElements()) {
095: ZipEntry entry = entries.nextElement();
096: if (entry.getName().endsWith(".tld")) {
097: URL tagLibUrl = new URL(facesConfigUrl.toString()
098: .split("!")[0]
099: + "!/" + entry.getName());
100: DocumentBuilderFactory factory = DocumentBuilderFactory
101: .newInstance();
102: factory.setValidating(false);
103: DocumentBuilder documentBuilder = factory
104: .newDocumentBuilder();
105: documentBuilder
106: .setEntityResolver(new EmptyEntityResolver());
107: Document tagLibdocument = documentBuilder
108: .parse(tagLibUrl.openStream());
109: NodeList tagNodes = tagLibdocument
110: .getElementsByTagName("uri");
111: // Scan the TLD file to find the taglib URI
112: String taglibUri = tagNodes.item(0).getTextContent()
113: .trim();
114:
115: TagLibFacesConfigInfo tagLibFacesConfigInfo = new TagLibFacesConfigInfo(
116: taglibUri);
117: tagLibFacesConfigInfo.addTagLibUrl(tagLibUrl);
118: tagLibFacesConfigInfo.addFacesConfigUrl(facesConfigUrl);
119:
120: statictTaglibFacesConfigLocationMap.put(taglibUri,
121: tagLibFacesConfigInfo);
122: }
123: }
124: }
125:
126: /**
127: *Factory Method to get TagLibrarySupport for a particular taglibUri and ClassLoader
128: */
129: public static JsfTagSupport getInstance(String taglibUri)
130: throws JsfTagSupportException, SAXException,
131: ParserConfigurationException, IOException {
132: synchronized (lock) {
133: if (!cachedTagLibraryInfoMap.containsKey(taglibUri)) {
134: cachedTagLibraryInfoMap.put(taglibUri,
135: new JsfTagSupport(taglibUri));
136: }
137:
138: }
139: return cachedTagLibraryInfoMap.get(taglibUri);
140: }
141:
142: public Object getTagHandler(ClassLoader classLoader, String tagName)
143: throws ClassNotFoundException, InstantiationException,
144: IllegalAccessException {
145: TagInfo tagInfo = tagInfoMap.get(tagName);
146: return classLoader.loadClass(tagInfo.getTagClass())
147: .newInstance();
148: }
149:
150: public Object getComponent(ClassLoader classLoader, String tagName)
151: throws ClassNotFoundException, InstantiationException,
152: IllegalAccessException {
153: UIComponentTagBase componentTag = (UIComponentTagBase) getTagHandler(
154: classLoader, tagName);
155: String componentType = componentTag.getComponentType();
156: ComponentInfo componentInfo = componentInfoMap
157: .get(componentType);
158: String componentClass = componentInfo.getComponentClass();
159: return classLoader.loadClass(componentClass).newInstance();
160: }
161:
162: public String getComponentClass(ClassLoader classLoader,
163: String tagName) throws ClassNotFoundException,
164: InstantiationException, IllegalAccessException {
165: UIComponentTagBase componentTag = (UIComponentTagBase) getTagHandler(
166: classLoader, tagName);
167: String componentType = componentTag.getComponentType();
168: ComponentInfo componentInfo = componentInfoMap
169: .get(componentType);
170: return componentInfo.getComponentClass();
171: }
172:
173: private JsfTagSupport(String taglibUri)
174: throws JsfTagSupportException, SAXException,
175: ParserConfigurationException, IOException {
176: TagLibFacesConfigInfo tagLibFacesConfigInfo = statictTaglibFacesConfigLocationMap
177: .get(taglibUri);
178:
179: if (tagLibFacesConfigInfo != null) {
180: DocumentBuilderFactory factory = DocumentBuilderFactory
181: .newInstance();
182: factory.setValidating(false);
183: List<URL> tagLibUrlList = tagLibFacesConfigInfo
184: .getTagLibUrls();
185: for (URL tagLibUrl : tagLibUrlList) {
186: // Create the builder and parse XML data from input stream
187: DocumentBuilder documentBuilder = factory
188: .newDocumentBuilder();
189: documentBuilder
190: .setEntityResolver(new EmptyEntityResolver());
191: Document tagLibdocument = documentBuilder
192: .parse(tagLibUrl.openStream());
193: parseTagLibary(tagLibdocument);
194: }
195:
196: List<URL> facesConfigUrlList = tagLibFacesConfigInfo
197: .getFacesConfigUrls();
198: for (URL facesConfigUrl : facesConfigUrlList) {
199: // Create the builder and parse XML data from input stream
200: DocumentBuilder documentBuilder = factory
201: .newDocumentBuilder();
202: documentBuilder
203: .setEntityResolver(new EmptyEntityResolver());
204: Document facesConfigdocument = documentBuilder
205: .parse(facesConfigUrl.openStream());
206: parseFacesConfig(facesConfigdocument);
207: }
208: } else {
209: throw new JsfTagSupportException(NbBundle.getMessage(
210: JsfTagSupport.class, "UNRECOGNIZED_TAGLIB")
211: + taglibUri);
212: }
213: }
214:
215: private Map<String, ComponentInfo> parseFacesConfig(
216: Document facesConfigdocument) {
217: NodeList componentNodes = facesConfigdocument
218: .getElementsByTagName("component");
219: for (int i = 0; i < componentNodes.getLength(); i++) {
220: ComponentInfo componentInfo = new ComponentInfo(
221: componentNodes.item(i));
222: componentInfoMap.put(componentInfo.getComponentType(),
223: componentInfo);
224: }
225:
226: return componentInfoMap;
227: }
228:
229: private void parseTagLibary(Document tagLibdocument) {
230: NodeList tagNodes = tagLibdocument.getElementsByTagName("tag");
231: for (int i = 0; i < tagNodes.getLength(); i++) {
232: TagInfo tagInfo = new TagInfo(tagNodes.item(i));
233: tagInfoMap.put(tagInfo.getName(), tagInfo);
234: }
235: }
236:
237: private static class TagLibFacesConfigInfo {
238:
239: private String taglibUri;
240: private List<URL> tagLibUrls = new ArrayList<URL>(3);
241: private List<URL> facesConfigUrls = new ArrayList<URL>(3);
242:
243: TagLibFacesConfigInfo(String taglibUri) {
244: this .taglibUri = taglibUri;
245: }
246:
247: public void addTagLibUrl(URL taglib) {
248: tagLibUrls.add(taglib);
249: }
250:
251: public List<URL> getTagLibUrls() {
252: return tagLibUrls;
253: }
254:
255: public void addFacesConfigUrl(URL facesConfig) {
256: facesConfigUrls.add(facesConfig);
257: }
258:
259: public List<URL> getFacesConfigUrls() {
260: return facesConfigUrls;
261: }
262: }
263:
264: private static class TagInfo {
265:
266: private String tagName;
267: private String tagClass;
268:
269: TagInfo(Node tagNode) {
270: Node nameNode = ((Element) tagNode).getElementsByTagName(
271: "name").item(0);
272: tagName = nameNode.getTextContent().trim();
273: Node tagClassNode = ((Element) tagNode)
274: .getElementsByTagName("tag-class").item(0);
275: tagClass = tagClassNode.getTextContent().trim();
276: }
277:
278: public String getName() {
279: return tagName;
280: }
281:
282: public String getTagClass() {
283: return tagClass;
284: }
285: }
286:
287: private static class ComponentInfo {
288:
289: private String componentType;
290: private String componentClass;
291:
292: ComponentInfo(Node componentNode) {
293: Node componentTypeNode = ((Element) componentNode)
294: .getElementsByTagName("component-type").item(0);
295: componentType = componentTypeNode.getTextContent().trim();
296: Node componentClassNode = ((Element) componentNode)
297: .getElementsByTagName("component-class").item(0);
298: componentClass = componentClassNode.getTextContent().trim();
299: }
300:
301: public String getComponentType() {
302: return componentType;
303: }
304:
305: public String getComponentClass() {
306: return componentClass;
307: }
308: }
309:
310: private static class EmptyEntityResolver implements EntityResolver {
311: public InputSource resolveEntity(String pubid, String sysid) {
312: return new InputSource(
313: new ByteArrayInputStream(new byte[0]));
314: }
315: }
316: }
|