/*******************************************************************************
* Copyright (c) 2012 gavingui2011@gmail.com
* All rights reserved. This program and the accompanying materials
* are 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:
* gavingui2011@gmail.com - initial API and implementation
*
*******************************************************************************/
package org.eclipse.wst.xml.ui.internal.contentassist.tapestry;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.tapestrytools.ui.internal.tcc.editor.ComponentPackage;
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.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.wst.xml.core.internal.contentmodel.tapestry.travelpackage.TapestryClassLoader;
import org.eclipse.wst.xml.core.internal.contentmodel.tapestry.travelpackage.TapestryCoreComponents;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class TapestryRootComponentsProposalComputer {
private String webXMLPath = null;
private List<Template> components = new ArrayList<Template>();
public List<Template> getRootComponentsAttributes(IProject project, String contextTypeId, String nodeName){
try {
IJavaElement[] elements = getComponentsJavaElements(project);
components.clear();
for(IJavaElement ele : elements){
if(ele.getElementType() == IJavaElement.COMPILATION_UNIT && ele.getElementName().endsWith(".java")){
String name = ele.getElementName().substring(0, ele.getElementName().indexOf('.'));
if( ("t:" + name).toLowerCase().equals(nodeName.toLowerCase())){
goThroughClass((ICompilationUnit) ele, contextTypeId);
}
}
}
return components;
} catch (JavaModelException e) {
e.printStackTrace();
}
return null;
}
private void goThroughClass(ICompilationUnit ClassContent, final String contextTypeId) {
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(ClassContent);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
final CompilationUnit cu = (CompilationUnit) parser.createAST(null);
cu.accept(new ASTVisitor() {
private boolean parameter = false;
private String paramName = "";
public void endVisit(FieldDeclaration node) {
paramName = "";
parameter = false;
node.accept(new ASTVisitor() {
public void endVisit(MarkerAnnotation node) {
parameter = node.getTypeName().toString()
.equals(TapestryContants.ANNOTATION_PARAMETER);
super.endVisit(node);
}
public void endVisit(NormalAnnotation node) {
parameter = node.getTypeName().toString()
.equals(TapestryContants.ANNOTATION_PARAMETER);
List values = node.values();
for (int i = 0; i < values.size(); i++) {
MemberValuePair pair = (MemberValuePair) values
.get(i);
if (pair.getName().toString().equals("read")
&& pair.getValue().toString()
.equals("false"))
parameter = false;
}
super.endVisit(node);
}
public void endVisit(VariableDeclarationFragment node) {
paramName = node.getName().toString();
super.endVisit(node);
}
});
super.endVisit(node);
if (parameter){
Template template = new Template(paramName, "add attribute " + paramName, contextTypeId, buildAttributeInsertCode(paramName), true);
components.add(template);
}
}
});
}
private static String buildAttributeInsertCode(String parameter){
String ret = parameter + "=\"${cursor}\"";
return ret;
}
/**
* Get components template list in situation:<span t:type="${component name here}"></span>
*
* @param project
* @param contextTypeId
* @return
*/
public List<Template> getRootComponentsNameTemplates(IProject project, String contextTypeId){
try {
IJavaElement[] elements = getComponentsJavaElements(project);
List<Template> components = new ArrayList<Template>();
for(IJavaElement ele : elements){
if(ele.getElementType() == IJavaElement.COMPILATION_UNIT && ele.getElementName().endsWith(".java")){
TapestryCoreComponents component = new TapestryCoreComponents();
String name = ele.getElementName().substring(0, ele.getElementName().indexOf('.'));
component.setName(name);
component.setElementLabel("t:" + name.toLowerCase());
components.add(new Template("t:" + component.getName(), buildDescription(component, "root package"), contextTypeId, component.getName(), true));
}
}
return components;
} catch (JavaModelException e) {
e.printStackTrace();
}
return null;
}
public List<Template> getRootComponentsTemplates(IProject project, String contextTypeId, int type){
try {
IJavaElement[] elements = getComponentsJavaElements(project);
List<Template> components = new ArrayList<Template>();
for(IJavaElement ele : elements){
if(ele.getElementType() == IJavaElement.COMPILATION_UNIT && ele.getElementName().endsWith(".java")){
TapestryCoreComponents component = new TapestryCoreComponents();
String name = ele.getElementName().substring(0, ele.getElementName().indexOf('.'));
component.setName(name);
component.setElementLabel("t:" + name.toLowerCase());
components.add(new Template("t:" + component.getName(), buildDescription(component, "root package"), contextTypeId, buildInsertCode(component, type), true));
}
}
return components;
} catch (JavaModelException e) {
e.printStackTrace();
}
return null;
}
private IJavaElement[] getComponentsJavaElements(IProject project) throws JavaModelException{
findWEBXML(project);
if(this.webXMLPath == null)
return null;
String rootPackage = parseRootPackage(project);
if(rootPackage == null || rootPackage.isEmpty())
return null;
rootPackage = rootPackage + ".components";
IPackageFragment pack = getTapestryRootComponentsPackage(project, rootPackage);
IJavaElement[] elements = pack.getChildren();
return elements;
}
private String buildDescription(TapestryCoreComponents component, String rootPackage){
return "Custom Component in " + rootPackage;
}
private String buildInsertCode(TapestryCoreComponents element, int type){
String ret = "";
String insertLabel = element.getElementLabel();
switch(type){
case 1:
ret = "<"+insertLabel+"></"+insertLabel+">";
break;
case 2:
ret = insertLabel+"></"+insertLabel+">";
break;
case 3:
ret = insertLabel+"></"+insertLabel+">";
int prefixLength = insertLabel.indexOf(':') + 1;
if(ret.length() > prefixLength)
ret = ret.substring(prefixLength);
break;
}
return ret;
}
public IPackageFragment getTapestryRootComponentsPackage(IProject project, String packageName) {
IPackageFragmentRoot[] roots2;
try {
roots2 = JavaCore.create(project).getAllPackageFragmentRoots();
for (IPackageFragmentRoot root : roots2) {
if (!root.isArchive()){
IPackageFragment packInstance = root.getPackageFragment(packageName);
if(packInstance != null)
return packInstance;
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return null;
}
private void findWEBXML(IProject project){
IResource[] fileList = null;
try {
fileList = project.members(false);
travelAllFolder(fileList);
} catch (CoreException e) {
e.printStackTrace();
}
}
private void travelAllFolder(IResource[] fileList)
throws CoreException {
for (int i = 0; i < fileList.length; i++) {
IResource eachFile = fileList[i];
if(eachFile.getType() == IResource.FILE && eachFile.getName().equals(TapestryContants.WEB_XML)){
this.webXMLPath = eachFile.getFullPath().toString();
return;
} else if (eachFile.getType() == IResource.FOLDER) {
IFolder file = (IFolder) eachFile;
travelAllFolder(file.members());
}
}
}
private String parseRootPackage(IProject project){
IResource webRes = project.findMember(webXMLPath.substring(("/" + project.getName()).length()));
if(webRes != null && webRes.getType() == IResource.FILE){
InputStream webStream;
try {
webStream = ResourcesPlugin.getWorkspace().getRoot()
.getFile(webRes.getFullPath()).getContents();
DocumentBuilder db=DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document=db.parse(webStream);
Element web = document.getDocumentElement();
NodeList filters = web.getChildNodes();
boolean tapestryContext = false;
String rootPath = null;
for(int i=0; i<filters.getLength(); i++){
Node filter=filters.item(i);
if(filter.getNodeType() != Node.ELEMENT_NODE || !filter.getNodeName().equals(TapestryContants.CONTEXT_PARAM))
continue;
NodeList filterChildren = filter.getChildNodes();
for(int j=0; j<filterChildren.getLength(); j++){
Node element = filterChildren.item(j);
if(element.getNodeType() != Node.ELEMENT_NODE)
continue;
if(element.getNodeName().equals(TapestryContants.PARAM_NAME)){
if(element.getTextContent().trim().equals(TapestryContants.PARAM_NAME_DEFINE)){
tapestryContext = true;
}
}else if(element.getNodeName().equals(TapestryContants.PARAM_VALUE)){
rootPath = element.getTextContent().trim();
}
}
if(rootPath != null && tapestryContext)
return rootPath;
}
} catch (CoreException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* Get all the prefixes including "t:" in current project
*
* @param project
* @return
*/
public Set<String> getComponentsPrefixList(IProject project){
Set<String> prefixList = new HashSet<String>();
prefixList.add("t");
final IFile res = project.getFile(TapestryContants.CUSTOM_COMPONENTS_FILE);
if(res == null)
return prefixList;
List<ComponentPackage> packageList = loadPackageList(res, 1, "");
for(ComponentPackage cp : packageList){
prefixList.add(cp.getPrefix());
}
return prefixList;
}
/**
* Get custom component attribute templates
*
* @param project
* @param contextTypeId
* @param nodeName
* @param tapestryClassLoader
* @return
*/
public List<Template> getCustomComponentsAttributes(IProject project, String contextTypeId, String nodeName, TapestryClassLoader tapestryClassLoader){
components.clear();
String prefix = nodeName.substring(0, nodeName.indexOf(':'));
try {
final IFile res = project.getFile(TapestryContants.CUSTOM_COMPONENTS_FILE);
if(res == null || prefix == null)
return components;
List<ComponentPackage> packageList = loadCustomComponentsPackageListWithPrefix(res, prefix);
IPackageFragmentRoot[] roots = JavaCore.create(project).getAllPackageFragmentRoots();
for(ComponentPackage cp : packageList){
for (IPackageFragmentRoot root : roots) {
if(cp.isArchive() == root.isArchive() && cp.getFragmentRoot().equals(root.getElementName())){
IPackageFragment packInstance = root.getPackageFragment(cp.getPath());
if (!root.isArchive()){
//If current custom component is in source directory
if(packInstance != null){
IJavaElement[] elements = packInstance.getChildren();
for(IJavaElement ele : elements){
if(ele.getElementType() == IJavaElement.COMPILATION_UNIT && ele.getElementName().endsWith(".java")){
String name = ele.getElementName().substring(0, ele.getElementName().indexOf('.'));
if((prefix + ":" + name).toLowerCase().equals(nodeName)){
goThroughClass((ICompilationUnit) ele, contextTypeId);
return components;
}
}
}
}
}else if(packInstance instanceof PackageFragment){
//Current custom component is in jar files
for(Object packo : ((PackageFragment) packInstance).getChildrenOfType(IJavaElement.CLASS_FILE)){
ClassFile packi = (ClassFile) packo;
String className = packi.getElementName().substring(0, packi.getElementName().indexOf('.'));
if(className.indexOf('$') < 0 && (prefix + ":" + className.toLowerCase()).equals(nodeName)){
TapestryCoreComponents component = null;
try {
component = tapestryClassLoader.loadComponentAttributesFromClassFile(root, prefix, packi);
} catch (ClassFormatException e) {
e.printStackTrace();
}
if(component != null){
for(String paramName : component.getPamameters()){
Template template = new Template(paramName, "add attribute " + paramName, contextTypeId, buildAttributeInsertCode(paramName), true);
components.add(template);
}
return components;
}
}
}
}
}
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return null;
}
/**
* Get Tapestry custom components in situation: <span t:type="${component name here}"></span>
*
* @param project
* @param contextTypeId
* @param type
* @param prefix
* @return
*/
public List<Template> getCustomComponentsNameTemplates(IProject project, String contextTypeId){
List<Template> templateList = new ArrayList<Template>();
final IFile res = project.getFile(TapestryContants.CUSTOM_COMPONENTS_FILE);
if(res == null)
return templateList;
List<ComponentPackage> packageList = loadPackageList(res, 1, "*");
IPackageFragmentRoot[] roots;
try {
roots = JavaCore.create(project).getAllPackageFragmentRoots();
for(ComponentPackage cp : packageList){
loadCustomComponentsNameFromPackage(roots, contextTypeId, templateList, cp);
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return templateList;
}
/**
* Get all the template list(including core templates, root templates and custom component templates) in current project
*
* @param project
* @param contextTypeId
* @param type
* @param prefix
* @return
*/
public List<Template> getCustomComponentsTemplates(IProject project, String contextTypeId, int type, String prefix){
List<Template> templateList = new ArrayList<Template>();
final IFile res = project.getFile(TapestryContants.CUSTOM_COMPONENTS_FILE);
if(res == null)
return templateList;
List<ComponentPackage> packageList = loadPackageList(res, type, prefix);
try {
IPackageFragmentRoot[] roots = JavaCore.create(project).getAllPackageFragmentRoots();
for(ComponentPackage cp : packageList){
loadCustomComponentsFromPackage(roots, contextTypeId, type, templateList, cp, prefix);
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return templateList;
}
/**
* Load component name template list, used in situation:<span t:type="${component name here}"></span>
*
* @param roots
* @param contextTypeId
* @param type
* @param templateList
* @param cp
*/
private void loadCustomComponentsNameFromPackage(IPackageFragmentRoot[] roots, String contextTypeId, List<Template> templateList, ComponentPackage cp){
List<String> componentNameList = getCustomComponentsNameList(roots, cp);
for(String componentName : componentNameList){
TapestryCoreComponents component = new TapestryCoreComponents();
component.setName(componentName);
component.setElementLabel(cp.getPrefix() + ":" + componentName.toLowerCase());
templateList.add(new Template(cp.getPrefix() + ":" + component.getName(), buildDescription(component, cp.getPath()), contextTypeId, cp.getPrefix()+ "/" +component.getName(), true));
}
}
/**
* Load custom component template list, used in situation:<t:prefix/compName
*
* @param roots
* @param contextTypeId
* @param type
* @param templateList
* @param cp
* @param prefix
*/
private void loadCustomComponentsFromPackage(IPackageFragmentRoot[] roots, String contextTypeId, int type, List<Template> templateList, ComponentPackage cp, String prefix){
List<String> componentNameList = getCustomComponentsNameList(roots, cp);
//Build templates from name list
for(String componentName : componentNameList){
TapestryCoreComponents component = new TapestryCoreComponents();
component.setName(componentName);
if (prefix == null || prefix.equals("t"))
component.setElementLabel("t:" + cp.getPrefix() + "." + componentName.toLowerCase());
else
component.setElementLabel(cp.getPrefix() + ":" + componentName.toLowerCase());
templateList.add(new Template(cp.getPrefix() + ":" + component.getName(), buildDescription(component,
cp.getPath()), contextTypeId, buildInsertCode(component, type), true));
}
}
private List<String> getCustomComponentsNameList(IPackageFragmentRoot[] roots, ComponentPackage cp){
List<String> componentNameList = new ArrayList<String>();
try {
for (IPackageFragmentRoot root : roots) {
if(root instanceof JarPackageFragmentRoot == cp.isArchive() && root.getElementName().equals(cp.getFragmentRoot())) {
if (!root.isArchive()) {
// Load custom components from source directory
IPackageFragment packInstance = root.getPackageFragment(cp.getPath());
if (packInstance != null) {
IJavaElement[] elements = packInstance.getChildren();
for (IJavaElement ele : elements) {
if (ele.getElementType() == IJavaElement.COMPILATION_UNIT
&& ele.getElementName().endsWith(".java")) {
String name = ele.getElementName().substring(0, ele.getElementName().indexOf('.'));
componentNameList.add(name);
}
}
}
} else {
// Load custom components from jar files
for (IJavaElement pack : root.getChildren()) {
if (pack != null && pack instanceof PackageFragment && pack.getElementName().equals(cp.getPath())) {
for(Object packo : ((PackageFragment) pack).getChildrenOfType(IJavaElement.CLASS_FILE)){
ClassFile packi = (ClassFile) packo;
String itemName = packi.getElementName();
if(itemName.indexOf('$') < 0 && itemName.endsWith(".class"))
componentNameList.add(itemName.substring(0, itemName.length()-6));
}
break;
}
}
}
return componentNameList;
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return componentNameList;
}
private List<ComponentPackage> loadPackageList(IFile res, int type, String prefix){
List<ComponentPackage> packageList = new ArrayList<ComponentPackage>();
DocumentBuilder db = null;
try {
db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document=db.parse(res.getContents());
Element root = document.getDocumentElement();
NodeList bundles = root.getChildNodes();
if (bundles != null) {
for (int i = 0; i < bundles.getLength(); i++) {
Node classCycles = bundles.item(i);
if (classCycles.getNodeType() == Node.ELEMENT_NODE
&& classCycles.getNodeName().trim().equals(TapestryContants.CUSTOM_COMPONENTS_PACKAGES)) {
NodeList classes = classCycles.getChildNodes();
for(int j=0; j<classes.getLength(); j++){
Node classItem = classes.item(j);
if(classItem.getNodeType() == Node.ELEMENT_NODE && classItem.getNodeName().trim().equals(TapestryContants.CUSTOM_COMPONENTS_PACKAGE)){
ComponentPackage ci = new ComponentPackage();
getPackageBasicInfo(ci, classItem);
if(type != 3 || ci.getPrefix().equals(prefix) || prefix.equals("t"))
packageList.add(ci);
}
}
break;
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
return packageList;
}
private List<ComponentPackage> loadCustomComponentsPackageListWithPrefix(IFile res, String prefix){
List<ComponentPackage> packageList = new ArrayList<ComponentPackage>();
DocumentBuilder db = null;
try {
db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document=db.parse(res.getContents());
Element root = document.getDocumentElement();
NodeList bundles = root.getChildNodes();
if (bundles != null) {
for (int i = 0; i < bundles.getLength(); i++) {
Node classCycles = bundles.item(i);
if (classCycles.getNodeType() == Node.ELEMENT_NODE
&& classCycles.getNodeName().trim().equals(TapestryContants.CUSTOM_COMPONENTS_PACKAGES)) {
NodeList classes = classCycles.getChildNodes();
for(int j=0; j<classes.getLength(); j++){
Node classItem = classes.item(j);
if(classItem.getNodeType() == Node.ELEMENT_NODE && classItem.getNodeName().trim().equals(TapestryContants.CUSTOM_COMPONENTS_PACKAGE)){
ComponentPackage ci = new ComponentPackage();
getPackageBasicInfo(ci, classItem);
if(ci.getPrefix().equals(prefix))
packageList.add(ci);
}
}
break;
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
return packageList;
}
/**
* Parse XML node
*
* @param ci
* @param classItem
*/
private void getPackageBasicInfo(ComponentPackage ci, Node classItem){
Node prefix = classItem.getAttributes().getNamedItem(TapestryContants.CUSTOM_COMPONENTS_PREFIX);
if (prefix != null)
ci.setPrefix(prefix.getNodeValue());
Node path = classItem.getAttributes().getNamedItem(TapestryContants.CUSTOM_COMPONENTS_PATH);
if (path != null)
ci.setPath(path.getNodeValue());
Node isArchive = classItem.getAttributes().getNamedItem(TapestryContants.CUSTOM_COMPONENTS_ISARCHIVE);
if(isArchive != null)
ci.setArchive(isArchive.getNodeValue().equals("true"));
Node fragmentRoot = classItem.getAttributes().getNamedItem(TapestryContants.CUSTOM_COMPONENTS_FRAGMENTROOT);
if(fragmentRoot != null)
ci.setFragmentRoot(fragmentRoot.getNodeValue());
}
}