/******************************************************************************* * Copyright (c) 2015 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.batch.internal.core.impl; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; 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.xml.core.internal.document.AttrImpl; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.jboss.tools.batch.core.BatchConstants; import org.jboss.tools.batch.core.BatchCorePlugin; import org.jboss.tools.common.EclipseUtil; import org.jboss.tools.common.text.ITextSourceReference; import org.jboss.tools.common.zip.UnzipOperation; import org.jboss.tools.jst.web.kb.KbQuery.Tag; import org.jboss.tools.jst.web.kb.WebKbPlugin; import org.osgi.framework.Bundle; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * @author Viacheslav Kabanovich * */ @SuppressWarnings("restriction") public class BatchUtil { /** * Implement this interface to pass object to Util.scanXMLFile() * * */ public static interface DocumentScanner { public void scanDocument(Document document); } /** * Utility method that receives IDOMDocument from IModelManager by file and after * invoking DocumentScanner.scanDocument(), releases the model. * * @param file * @param scanner */ public static void scanXMLFile(IFile file, DocumentScanner scanner) { IModelManager manager = StructuredModelManager.getModelManager(); if(manager != null) { IStructuredModel model = null; try { model = manager.getModelForRead(file); if (model instanceof IDOMModel) { IDOMModel domModel = (IDOMModel) model; IDOMDocument document = domModel.getDocument(); if(document != null) { scanner.scanDocument(document); } } } catch (CoreException e) { WebKbPlugin.getDefault().logError(e); } catch (IOException e) { WebKbPlugin.getDefault().logError(e); } finally { if (model != null) { model.releaseFromRead(); } } } } /** * Returns collection of text source references in xml file to attribute by name and value. * * @param file * @param attr * @param value * @return */ public static List<TextSourceReference> getAttributeReferences(IFile file, String name, String value) { String expression = "//*[@" + name + "=\"" + value + "\"]/@" + name; AttrReferencesRequestor<TextSourceReference> requestor = new AttrReferencesRequestor<TextSourceReference>(file, expression, TextSourceReference.class); scanXMLFile(file, requestor); return requestor.results; } /** * Returns collection of text source references in xml file to name attribute of property tag by refValue and nameValue * * @param file * @param refValue value of ref attribute * @param nameValue value of name attribute * @return */ public static List<TextSourceReference> getPropertyAttributeReferences(IFile file, String refValue, String propertyName) { String expression = "//*[@"+BatchConstants.ATTR_REF+"=\""+refValue+"\"]//*[@" + BatchConstants.ATTR_NAME + "=\"" + propertyName + "\"]/@" + BatchConstants.ATTR_NAME; AttrReferencesRequestor<TextSourceReference> requestor = new AttrReferencesRequestor<TextSourceReference>(file, expression, TextSourceReference.class); scanXMLFile(file, requestor); return requestor.results; } /** * Returns collection of text source references in xml file to name attribute of property tag by refValue and nameValue * * @param file * @param refValue value of ref attribute * @param nameValue value of name attribute * @return */ public static List<NodePathTextSourceReference> getNodePathPropertyAttributeReferences(IFile file, String refValue, String propertyName) { String expression = "//*[@"+BatchConstants.ATTR_REF+"=\""+refValue+"\"]//*[@" + BatchConstants.ATTR_NAME + "=\"" + propertyName + "\"]/@" + BatchConstants.ATTR_NAME; AttrReferencesRequestor<NodePathTextSourceReference> requestor = new AttrReferencesRequestor<NodePathTextSourceReference>(file, expression, NodePathTextSourceReference.class); scanXMLFile(file, requestor); return requestor.results; } public static class AttrReferencesRequestor<E extends TextSourceReference> implements DocumentScanner { IFile file; String expression; List<E> results = new ArrayList<E>(); Class<E> cls; public AttrReferencesRequestor(IFile file, String expression, Class<E> cls) { this.file = file; this.expression = expression; this.cls = cls; } @Override public void scanDocument(Document document) { XPath xPath = XPathFactory.newInstance().newXPath(); try { Object result = xPath.compile(expression).evaluate(document, XPathConstants.NODESET); if(result instanceof NodeList) { NodeList list = (NodeList)result; for (int i = 0; i < list.getLength(); i++) { Node n = list.item(i); if(n instanceof AttrImpl) { AttrImpl a = (AttrImpl)n; int start0 = a.getValueRegionStartOffset(); int length0 = a.getValueRegionText().length(); if(a.getValueRegionText().startsWith("\"")) { start0++; length0 -= 2; } final int start = start0; final int length = length0; try{ E ref = cls.newInstance(); ref.setLength(length); ref.setResource(file); ref.setStartPosition(start); ref.setNodePath(n); results.add(ref); }catch(InstantiationException e){ }catch(IllegalAccessException e){ } } } } } catch (XPathExpressionException e) { BatchCorePlugin.pluginLog().logError(e); } } public List<E> getResults() { return results; } } private static List<Tag> getNodePath(Node node){ ArrayList<Tag> tags = new ArrayList<Tag>(); Node n = node; if(n instanceof AttrImpl){ n = ((AttrImpl) node).getOwnerElement(); } while(!(n instanceof IDOMDocument) && n != null){ HashMap<String, String> attributes = new HashMap<String, String>(); if(n.hasAttributes()){ NamedNodeMap attrs = n.getAttributes(); for(int index = 0; index < attrs.getLength(); index++){ Node attribute = attrs.item(index); attributes.put(attribute.getNodeName(), attribute.getNodeValue()); } } Tag tag = new Tag(n.getNodeName(), attributes); tags.add(tag); n = n.getParentNode(); } return tags; } private static File TEMPLATE_FOLDER; public static File getTemplatesFolder() throws IOException { if(TEMPLATE_FOLDER == null) { Bundle bundle = BatchCorePlugin.getDefault().getBundle(); String version = bundle.getVersion().toString(); IPath stateLocation = Platform.getStateLocation(bundle); File templatesDir = FileLocator.getBundleFile(bundle); if(templatesDir.isFile()) { File toCopy = new File(stateLocation.toFile(),version); if(!toCopy.exists()) { toCopy.mkdirs(); UnzipOperation unZip = new UnzipOperation(templatesDir.getAbsolutePath()); unZip.execute(toCopy, "templates.*"); } templatesDir = toCopy; } TEMPLATE_FOLDER = new File(templatesDir, "templates"); } return TEMPLATE_FOLDER; } /** * Returns path to existing batch.xml, or to implied batch.xml in Java source folder, * or null, if there is no source folders. * * @param p * @return */ public static IPath getBatchXMLPath(IProject p) { IPath result = null; for (IResource f: EclipseUtil.getJavaSourceRoots(p)) { if(f instanceof IFolder) { IFolder fm = ((IFolder)f).getFolder(BatchConstants.META_INF); IFile batch = fm.getFile(BatchConstants.BATCH_XML); if(batch.exists()) { return batch.getFullPath(); } else if(result == null || fm.exists()) { result = batch.getFullPath(); } } } return result; } public static class TextSourceReference implements ITextSourceReference{ private IResource resource; int startPosition; int length; public TextSourceReference(){ } @Override public int getStartPosition() { return startPosition; } @Override public int getLength() { return length; } @Override public IResource getResource() { return resource; } public void setResource(IResource resource) { this.resource = resource; } public void setStartPosition(int startPosition) { this.startPosition = startPosition; } public void setLength(int length) { this.length = length; } public void setNodePath(Node node){ } } public static class NodePathTextSourceReference extends TextSourceReference{ private List<Tag> tags; public Collection<Tag> getNodePath(){ return tags; } public void setNodePath(Node node){ this.tags = BatchUtil.getNodePath(node); } } }