/******************************************************************************* * Copyright (c) 2007-2010 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.jsf.jsf2.model; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Scanner; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.internal.core.JarEntryFile; import org.eclipse.jface.text.IDocument; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.DocumentProviderRegistry; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.wst.html.core.internal.encoding.HTMLModelLoader; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import org.eclipse.wst.sse.core.internal.text.JobSafeStructuredDocument; import org.eclipse.wst.xml.core.internal.document.ElementImpl; import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.eclipse.wst.xml.core.internal.provisional.format.DocumentNodeFormatter; import org.jboss.tools.jsf.JSFModelPlugin; import org.jboss.tools.jsf.jsf2.util.JSF2ResourceUtil; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * @author yzhishko * */ @SuppressWarnings("restriction") public class JSF2ComponentModelManager { public final static String INTERFACE = "interface"; public final static String ATTRIBUTE = "attribute"; public final static String NAME = "name"; public final static String XMLNS = "xmlns"; public final static String COLON = ":"; public final static String DEFAULT_COMPOSITE_PREFIX = "composite"; public final static String XHTML_URI = "http://www.w3.org/1999/xhtml"; public final static String HTML = "html"; public final static String HTML_URI = "http://java.sun.com/jsf/html"; public final static String HTML_PREFIX = "h"; private static JSF2ComponentModelManager instance = new JSF2ComponentModelManager(); private JSF2ComponentModelManager() { } public static JSF2ComponentModelManager getManager() { return instance; } public IFile updateJSF2CompositeComponentFile( final IFile componentFileContatiner, final String[] attrNames) { IFile file = updateFileContent(new EditableDOMFile() { @Override public IFile getFile() { return componentFileContatiner; } @Override protected void edit(IDOMModel model) throws CoreException, IOException { FileEditorInput input = new FileEditorInput(getFile()); IDocumentProvider provider = DocumentProviderRegistry.getDefault().getDocumentProvider(input); provider.connect(input); IDocument document = provider.getDocument(input); updateJSF2CompositeComponent(model.getDocument(), attrNames); provider.aboutToChange(input); provider.saveDocument(new NullProgressMonitor(), input, document, true); provider.changed(input); provider.disconnect(input); } }); return file; } private void updateJSF2CompositeComponent(IDOMDocument componentDoc, String[] attrNames) { Element interfaceElement = findInterfaceComponent(componentDoc); if(interfaceElement == null) interfaceElement = createCompositeInterface(componentDoc); createCompositeCompInterface(interfaceElement, attrNames); } private Element findInterfaceComponent(Node node) { if (node instanceof IDOMDocument) { IDOMDocument document = (IDOMDocument) node; Element element = findInterfaceComponent(document.getDocumentElement()); if(element != null) return element; } if (node instanceof ElementImpl) { ElementImpl impl = (ElementImpl) node; String nameSpace = impl.getNamespaceURI(); if (CompositeComponentConstants.COMPOSITE_XMLNS.equals(nameSpace)) { String nodeName = impl.getLocalName(); if (INTERFACE.equals(nodeName)) { //$NON-NLS-1$ return impl; } } else { NodeList nodeList = node.getChildNodes(); if (nodeList != null) { for (int i = 0; i < nodeList.getLength(); i++) { Element element = findInterfaceComponent(nodeList.item(i)); if(element != null) return element; } } } } return null; } private void createCompositeCompInterface(Element element, String[] attrNames) { Document document = (Document) element.getOwnerDocument(); String prefix = element.getPrefix(); Set<String> existInerfaceAttrs = getInterfaceAttrs(element); if (prefix != null && !"".equals(prefix)) { //$NON-NLS-1$ for (int i = 0; i < attrNames.length; i++) { if (!existInerfaceAttrs.contains(attrNames[i])) { Element attrEl = document.createElementNS( CompositeComponentConstants.COMPOSITE_XMLNS, prefix + COLON+ATTRIBUTE); //$NON-NLS-1$ attrEl.setAttribute(NAME, attrNames[i]); //$NON-NLS-1$ element.appendChild(attrEl); } } } else { for (int i = 0; i < attrNames.length; i++) { if (!existInerfaceAttrs.contains(attrNames[i])) { Element attrEl = document.createElementNS( CompositeComponentConstants.COMPOSITE_XMLNS, ATTRIBUTE); //$NON-NLS-1$ attrEl.setAttribute(NAME, attrNames[i]); //$NON-NLS-1$ element.appendChild(attrEl); } } } DocumentNodeFormatter formatter = new DocumentNodeFormatter(); formatter.format(document); } public IFile revalidateCompositeComponentFile(IFile file) { IDOMDocument document = getReadableDOMDocument(file); if (document == null) { return null; } //Element interfaceElement = checkCompositeInterface(document); //if (interfaceElement == null) //return null; return file; } public Element checkCompositeInterface(IDOMDocument document) { if (document == null) { return null; } Element element = document.getDocumentElement(); if (element == null) { return null; } if(!hasNamespace(element, CompositeComponentConstants.COMPOSITE_XMLNS)) return null; return findInterfaceComponent(element); } private boolean hasNamespace(Node node, String URI){ NamedNodeMap attributes = node.getAttributes(); for(int i = 0; i < attributes.getLength(); i++){ Node attr = attributes.item(i); if(attr.getNodeName().startsWith(XMLNS+COLON) && URI.equals(attr.getNodeValue())) return true; } return false; } private String getPrefix(Node node, String URI){ NamedNodeMap attributes = node.getAttributes(); for(int i = 0; i < attributes.getLength(); i++){ Node attr = attributes.item(i); if(attr.getNodeName().startsWith(XMLNS+COLON) && URI.equals(attr.getNodeValue())) return attr.getLocalName(); } return null; } private Element findNodeToCreateCompositeInterface(Element rootNode){ if(hasNamespace(rootNode, CompositeComponentConstants.COMPOSITE_XMLNS)) return rootNode; NodeList children = rootNode.getChildNodes(); for(int i = 0; i < children.getLength(); i++){ Node child = children.item(i); if(child instanceof Element){ Node result = findNodeToCreateCompositeInterface((Element)child); if(result != null && result instanceof Element) return (Element)result; } } return null; } private Element createCompositeInterface(Document document){ Element rootElement = document.getDocumentElement(); if (rootElement == null) { rootElement = createDocumentElementForCompositeInterface(document); } Element node = findNodeToCreateCompositeInterface(rootElement); if(node == null){ addURI(document, rootElement); node = rootElement; } String prefix = getPrefix(node, CompositeComponentConstants.COMPOSITE_XMLNS); Element interfaceElement = document.createElement(prefix+COLON+INTERFACE); node.appendChild(interfaceElement); DocumentNodeFormatter formatter = new DocumentNodeFormatter(); formatter.format(document); return interfaceElement; } private Element createDocumentElementForCompositeInterface(Document document){ Element rootElement = document.createElement(HTML); Attr attr = document.createAttribute(XMLNS); attr.setValue(XHTML_URI); rootElement.setAttributeNode(attr); attr = document.createAttribute(XMLNS+COLON+HTML_PREFIX); attr.setValue(HTML_URI); rootElement.setAttributeNode(attr); attr = document.createAttribute(XMLNS+COLON+DEFAULT_COMPOSITE_PREFIX); attr.setValue(CompositeComponentConstants.COMPOSITE_XMLNS); rootElement.setAttributeNode(attr); document.appendChild(rootElement); return rootElement; } private void addURI(Document document, Element rootElement){ Attr attr = document.createAttribute(XMLNS+COLON+DEFAULT_COMPOSITE_PREFIX); attr.setValue(CompositeComponentConstants.COMPOSITE_XMLNS); rootElement.setAttributeNode(attr); } public static IDOMDocument getReadableDOMDocument(IFile file) { IDOMDocument document = null; IModelManager manager = StructuredModelManager.getModelManager(); if (manager == null) { return document; } IStructuredModel model = null; try { model = manager.getModelForRead(file); if (model instanceof IDOMModel) { IDOMModel domModel = (IDOMModel) model; document = domModel.getDocument(); } } catch (CoreException e) { JSFModelPlugin.getPluginLog().logError(e); } catch (IOException e) { JSFModelPlugin.getPluginLog().logError(e); } finally { if (model != null) { model.releaseFromRead(); } } return document; } public static IDOMDocument getReadableDOMDocument(JarEntryFile file) { IDOMDocument document = null; IStructuredModel model = null; InputStream inputStream = null; try { inputStream = file.getContents(); if (inputStream != null) { StringBuilder buffer = new StringBuilder(); //$NON-NLS-1$ Scanner in = new Scanner(inputStream); while (in.hasNextLine()) { buffer.append(in.nextLine()); } model = new HTMLModelLoader().newModel(); model.setStructuredDocument(new JobSafeStructuredDocument( new XMLSourceParser())); model.getStructuredDocument().set(buffer.toString()); if (model instanceof IDOMModel) { document = ((IDOMModel) model).getDocument(); } } } catch (CoreException e) { JSFModelPlugin.getPluginLog().logError(e); } finally { if(inputStream!=null) { try { inputStream.close(); } catch (IOException e) { // Ignore } } model = null; } return document; } public static IDOMDocument getReadableDOMDocument(IDocument textDocument) { IDOMDocument document = null; if (!(textDocument instanceof IStructuredDocument)) { return document; } IModelManager manager = StructuredModelManager.getModelManager(); if (manager == null) { return document; } IStructuredModel model = null; try { model = manager.getModelForRead((IStructuredDocument) textDocument); if (model instanceof IDOMModel) { IDOMModel domModel = (IDOMModel) model; document = domModel.getDocument(); } } finally { if (model != null) { model.releaseFromRead(); } } return document; } public Set<String> getInterfaceAttrs(Element interfaceElement) { Set<String> interfaceAttrs = new HashSet<String>(0); if (interfaceElement != null) { String prefix = interfaceElement.getPrefix(); String nodeName = ATTRIBUTE; if (prefix != null && !"".equals(prefix)) { //$NON-NLS-1$ nodeName = prefix + COLON + nodeName; //$NON-NLS-1$ } NodeList attrsElements = interfaceElement .getElementsByTagName(nodeName); if (attrsElements != null) { for (int i = 0; i < attrsElements.getLength(); i++) { Node el = attrsElements.item(i); if (el instanceof IDOMElement) { IDOMElement element = (IDOMElement) el; String attrvalue = element.getAttribute(NAME); //$NON-NLS-1$ if (attrvalue != null && !"".equals(attrvalue)) { //$NON-NLS-1$ interfaceAttrs.add(attrvalue); } } } } } return interfaceAttrs; } private abstract class EditableDOMFile { public EditableDOMFile() { } public IFile editFile() { IFile file = getFile(); if (file == null) { return file; } IModelManager manager = StructuredModelManager.getModelManager(); if (manager == null) { return file; } IStructuredModel model = null; try { model = manager.getModelForEdit(file); if (model instanceof IDOMModel) { IDOMModel domModel = (IDOMModel) model; edit(domModel); } } catch (CoreException e) { JSFModelPlugin.getPluginLog().logError(e); } catch (IOException e) { JSFModelPlugin.getPluginLog().logError(e); } finally { if (model != null) { model.releaseFromEdit(); } } return file; }; protected abstract void edit(IDOMModel model) throws CoreException, IOException; public abstract IFile getFile(); } private IFile updateFileContent(EditableDOMFile domFile) { return domFile.editFile(); } }