package org.ofbiz.plugin;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
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.IMethodBinding;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.ResolvedSourceMethod;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.ofbiz.plugin.model.ComponentHelper;
import org.ofbiz.plugin.model.OfbizModelSingleton;
import org.ofbiz.plugin.ofbiz.AbstractViewMap;
import org.ofbiz.plugin.ofbiz.Component;
import org.ofbiz.plugin.ofbiz.Directory;
import org.ofbiz.plugin.ofbiz.OfbizFactory;
import org.ofbiz.plugin.ofbiz.Project;
import org.ofbiz.plugin.ofbiz.Root;
import org.ofbiz.plugin.ofbiz.ScreenViewMap;
import org.ofbiz.plugin.ofbiz.Service;
import org.ofbiz.plugin.ofbiz.ServiceInvocation;
import org.ofbiz.plugin.ofbiz.WebApp;
import org.ofbiz.plugin.parser.ComponentParser;
import org.ofbiz.plugin.parser.DirectoryParser;
import org.ofbiz.plugin.parser.EntityParser;
import org.ofbiz.plugin.parser.FormParser;
import org.ofbiz.plugin.parser.ScreenParser;
import org.ofbiz.plugin.parser.SecaParser;
import org.ofbiz.plugin.parser.ServiceParser;
import org.ofbiz.plugin.parser.WebappParser;
import org.ofbiz.plugin.parser.model.WebappModel;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class LoadOperation extends WorkspaceModifyOperation {
private final Root root;
private Map<String, Service> serviceByName;
private Set<String> alreadyParsedJavaFiles = new HashSet<String>();
private List<String> screensToParse = new ArrayList<String>();
private List<IFile> secasToParse = new ArrayList<IFile>();
public LoadOperation(ExplorerView view) {
this(view.getRoot());
}
public LoadOperation(Root root) {
assert root != null;
this.root = root;
}
@Override
protected void execute(IProgressMonitor monitor)
throws CoreException, InvocationTargetException, InterruptedException {
monitor.beginTask("load OFBiz projects:", IProgressMonitor.UNKNOWN);
// clear
root.getProjects().clear();
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
wsRoot.deleteMarkers(Plugin.TEXT_MARKER, true, IResource.DEPTH_INFINITE);
wsRoot.deleteMarkers(Plugin.PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
monitor.worked(1);
// load open OFBiz projects
for(IProject project : wsRoot.getProjects()) {
if (!project.isOpen()) {
continue;
}
if (isOfbizProject(project)) {
load(project,monitor);
} else {
}
}
monitor.done();
}
private void load(IProject project, IProgressMonitor monitor) {
monitor.subTask("load project: "+project.getName());
// initialize domain object but don't add project to root until the end
Project ofbizProject = OfbizFactory.eINSTANCE.createProject();
ofbizProject.setName(project.getName());
ofbizProject.setJavaproject(JavaCore.create(project));
ofbizProject.setProject(project);
//eclipse project names are unique
OfbizModelSingleton.get().addProject(project.getName(), ofbizProject);
// parse project configuration
IResource res = project.findMember(Plugin.BASECONFIG);
if (res==null || !res.exists() || !(res instanceof IFile)) {
Plugin.logError("Project configuration does not exist: "+res.getName(), null);
return;
}
DirectoryParser parser = new DirectoryParser(ofbizProject);
try {
XmlPullParser xpp =
Plugin.getDefault().getXmlPullParserPool().getPullParserFromPool();
parser.processDocument(xpp, (IFile)res);
Plugin.getDefault().getXmlPullParserPool().returnPullParserToPool(xpp);
} catch (Exception e) {
Plugin.logError("Unable to parse configuration for project: "+project.getName(),e);
return;
}
monitor.worked(1);
// load each component directory
for(Directory directory : ofbizProject.getDirectories()) {
load(directory,monitor);
}
//load each screen
Set<String> parsedScreens = new HashSet<String>();
Set<String> nextFormsToParse = new HashSet<String>();
for(Directory directory : ofbizProject.getDirectories()) {
for (Component component : directory.getComponents()) {
for (WebApp webapp : component.getWebapps()) {
EList<AbstractViewMap> viewMaps = webapp.getController().getViewMaps();
for (AbstractViewMap viewMap : viewMaps) {
if (viewMap instanceof ScreenViewMap) {
ScreenViewMap screenViewMap = (ScreenViewMap) viewMap;
String screenLocation = screenViewMap.getViewName();
String screenUrl;
int indexOf = screenLocation.indexOf("#");
if (indexOf > 0) {
screenUrl = screenLocation.substring(0, indexOf);
} else {
screenUrl = screenLocation;
}
screensToParse.add(screenUrl);
}
}
while (screensToParse.size() > 0) {
String nextScreenToParse = screensToParse.remove(0);
if (!parsedScreens.contains(nextScreenToParse)) {
parsedScreens.add(nextScreenToParse);
IFile screenFile = null;
if (nextScreenToParse == null) {
continue;
}
Component componentByUrl = ComponentHelper.getComponentByUrl(ofbizProject, nextScreenToParse);
if (componentByUrl == null) {
continue;
}
try {
screenFile = (IFile) componentByUrl.getDirectory().getFolder().findMember(nextScreenToParse.substring("component://".length()));
} catch (NullPointerException e) {
}
if (screenFile != null) {
ScreenParser screenParser = new ScreenParser(screenFile, nextScreenToParse, ofbizProject);
XmlPullParser xpp;
try {
xpp = Plugin.getDefault().getXmlPullParserPool().getPullParserFromPool();
screenParser.processDocument(xpp, screenFile);
nextFormsToParse.addAll(screenParser.getForms());
screensToParse.addAll(screenParser.getScreens());
} catch (XmlPullParserException e) {
} catch (CoreException e) {
} catch (IOException e) {
}
}
}
}
}
}
}
for (String nextFormToParse :nextFormsToParse) {
IFile formFile = null;
try {
Component component = ComponentHelper.getComponentByUrl(ofbizProject, nextFormToParse);
formFile = (IFile) component.getDirectory().getFolder().findMember(nextFormToParse.substring("component://".length()));
} catch (NullPointerException e) {
}
if (formFile != null) {
XmlPullParser xpp;
try {
xpp = Plugin.getDefault().getXmlPullParserPool().getPullParserFromPool();
new FormParser(formFile, nextFormToParse, ofbizProject).processDocument(xpp, formFile);
} catch (XmlPullParserException e) {
} catch (CoreException e) {
} catch (IOException e) {
}
}
}
//Parse SECAs
for (IFile secaFile : secasToParse) {
SecaParser secaParser = new SecaParser();
XmlPullParser xpp;
try {
xpp = Plugin.getDefault().getXmlPullParserPool().getPullParserFromPool();
secaParser.processDocument(xpp, secaFile);
} catch (XmlPullParserException e) {
} catch (CoreException e) {
} catch (IOException e) {
}
}
// everything is ok so we can add the loaded project to the root
ofbizProject.setRoot(root);
//find all service usage
// findServiceUsage(ofbizProject);
}
private void findServiceUsage(Project ofbizProject) {
IJavaProject javaProject = ofbizProject.getJavaproject();
try {
IJavaSearchScope createWorkspaceScope = SearchEngine.createJavaSearchScope(new IResource[] {javaProject.getResource()});
SearchEngine searchEngine = new SearchEngine();
IType findType = javaProject.findType("org.ofbiz.service.LocalDispatcher");
IMethod[] methods = findType.getMethods();
for (IMethod method : methods) {
if (method.getElementName().startsWith("run")) {
SearchPattern pattern = SearchPattern.createPattern(method, IJavaSearchConstants.REFERENCES);
SearchRequestor requestor = new SearchRequestor() {
@Override
public void acceptSearchMatch(final SearchMatch searchMatch) throws CoreException {
ICompilationUnit createCompilationUnitFrom = JavaCore.createCompilationUnitFrom((IFile) searchMatch.getResource());
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(createCompilationUnitFrom);
parser.setResolveBindings(true);
CompilationUnit unit = (CompilationUnit) parser.createAST(null); // parse
unit.accept(new ASTVisitor() {
String javaDoc = null;
@Override
public boolean visit(Javadoc node) {
javaDoc = node.tags().toString();
return super.visit(node);
}
@Override
public boolean visit(MethodInvocation node) {
IMethodBinding resolveMethodBinding = node.resolveMethodBinding();
if (resolveMethodBinding == null) {
return false;
}
String methodName = resolveMethodBinding.getName();
if (methodName.startsWith("run") && methodName.length() > 3) {
if (node.arguments().size() == 2) {
Object firstArgObject = node.arguments().get(0);
if (firstArgObject instanceof StringLiteral) {
StringLiteral firstArg = (StringLiteral) firstArgObject;
String serviceName = firstArg.getLiteralValue().replaceAll("\"", "");
Service serviceByName = getServiceByName(serviceName);
if (serviceByName != null) {
ResolvedSourceMethod element = (ResolvedSourceMethod) searchMatch.getElement();
String alreadyParsedKey = element.getParent().getPath()+serviceName;
if (!alreadyParsedJavaFiles.contains(alreadyParsedKey)) {
ServiceInvocation createServiceInvocation = OfbizFactory.eINSTANCE.createServiceInvocation();
createServiceInvocation.setService(serviceByName);
createServiceInvocation.setName(element.getParent().getPath()+ "." + element.getElementName());
alreadyParsedJavaFiles.add(alreadyParsedKey);
}
}
}
}
}
return super.visit(node);
}
});
}
};
SearchParticipant searchParticipiant[] = new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()};
searchEngine.search(pattern, searchParticipiant, createWorkspaceScope, requestor, null);
}
}
} catch (Exception e) {
Plugin.logError("Ex", e);
}
}
private Service getServiceByName(String name) {
if (serviceByName == null) {
serviceByName = new HashMap<String, Service>();
for (Project project : root.getProjects()) {
for (Directory directory : project.getDirectories()) {
for (Component component : directory.getComponents()) {
for (Service service : component.getServices()) {
serviceByName.put(service.getName(), service);
}
}
}
}
}
return serviceByName.get(name);
}
private void load(Directory directory,IProgressMonitor monitor) {
monitor.subTask("load directory: "+directory.getName());
// load static directory or hot-deploy'ed directory
if (directory.getName().equals("hot-deploy")) {
loadDynamicDirectory(directory);
} else {
loadStaticDirectory(directory);
}
monitor.worked(1);
// load each component
for(Component component : directory.getComponents()) {
load(component,monitor);
}
}
private void loadDynamicDirectory(final Directory directory) {
// add a component for each folder
final IFolder folder = directory.getFolder();
try {
folder.accept(new IResourceVisitor(){
@Override
public boolean visit(IResource resource) throws CoreException {
if (resource instanceof IFolder && resource!=folder) {
IFolder componentFolder = (IFolder) resource;
Component component = OfbizFactory.eINSTANCE.createComponent();
component.setName(componentFolder.getName());
component.setFolder(componentFolder);
component.setDirectory(directory);
}
return true;
}
}, IResource.DEPTH_ONE, false);
} catch (CoreException e) {
Plugin.logError("Unable to load hot-deploy directory", e);
}
}
private void loadStaticDirectory(Directory directory) {
// parse directory configuration
DirectoryParser parser = new DirectoryParser(directory.getProject());
parser.setDirectory(directory);
IResource cfg = directory.getFolder().findMember("component-load.xml");
if(cfg==null || !cfg.exists() || !(cfg instanceof IFile)) {
Plugin.logError(
"Unable to locate directory configuration file: "
+directory.getName(), null);
return;
}
try {
XmlPullParser xpp =
Plugin.getDefault().getXmlPullParserPool().getPullParserFromPool();
parser.processDocument(xpp, (IFile)cfg);
Plugin.getDefault().getXmlPullParserPool().returnPullParserToPool(xpp);
} catch (Exception e) {
Plugin.logError("Unable to parse directory configuration: "+directory.getName(), e);
}
}
private void load(Component component,IProgressMonitor monitor) {
monitor.subTask("load component: "+component.getName());
// parse component configuration
ComponentParser parser = new ComponentParser(component);
IResource cfg = component.getFolder().findMember("ofbiz-component.xml");
component.setFile((IFile) cfg);
if(cfg==null || !cfg.exists() || !(cfg instanceof IFile)) {
Plugin.logError(
"Unable to locate component configuration file: "
+component.getName(), null);
return;
}
try {
XmlPullParser xpp =
Plugin.getDefault().getXmlPullParserPool().getPullParserFromPool();
parser.processDocument(xpp, (IFile) cfg);
Plugin.getDefault().getXmlPullParserPool().returnPullParserToPool(xpp);
parser.addMarker();
} catch (Exception e) {
Plugin.logError("Unable to parse component configuration: "+ component.getName(), e);
return;
}
monitor.worked(1);
// load entity models
for (final IFile file : parser.getEntityModels()) {
monitor.subTask("load entity model: "+file.getName());
loadEntityModel(component, file);
monitor.worked(1);
}
// load service models
for (final IFile file : parser.getServiceModels()) {
monitor.subTask("load service model: "+file.getName());
loadServiceModel(component, file);
monitor.worked(1);
}
secasToParse.addAll(parser.getSecaModels());
// load webapp models
for (final WebappModel webappModel : parser.getWebappModels()) {
IFile file = webappModel.getiFile();
monitor.subTask("load webapp model: "+file.getName());
loadWebappModel(component, file, webappModel.getUri());
monitor.worked(1);
}
}
private void loadEntityModel(Component component, IFile file) {
try {
EntityParser parser = new EntityParser(component);
XmlPullParser xpp = Plugin.getDefault()
.getXmlPullParserPool().getPullParserFromPool();
parser.processDocument(xpp, file);
Plugin.getDefault().getXmlPullParserPool().returnPullParserToPool(xpp);
} catch (Exception e) {
Plugin.logError("Unable to parse entitymodel: "+ file.getName(), e);
}
}
private void loadServiceModel(Component component, IFile file) {
try {
ServiceParser parser = new ServiceParser(component);
XmlPullParser xpp = Plugin.getDefault()
.getXmlPullParserPool().getPullParserFromPool();
parser.processDocument(xpp, file);
Plugin.getDefault().getXmlPullParserPool().returnPullParserToPool(xpp);
} catch (Exception e) {
Plugin.logError("Unable to parse servicemodel: "+ file.getName(), e);
}
}
private void loadWebappModel(Component component, IFile file, String uri) {
try {
WebappParser parser = new WebappParser(component, uri, file);
XmlPullParser xpp = Plugin.getDefault()
.getXmlPullParserPool().getPullParserFromPool();
parser.processDocument(xpp, file);
screensToParse.addAll(parser.getScreenLocations());
Plugin.getDefault().getXmlPullParserPool().returnPullParserToPool(xpp);
} catch (Exception e) {
Plugin.logError("Unable to parse webapp model: "+ file.getName(), e);
}
}
/** Checks whether a project contains an OFBiz app. Closed projects always return false. */
private boolean isOfbizProject(IProject project) {
if (!project.isOpen()) return false;
IResource config =
project.findMember(Plugin.BASECONFIG);
return config != null && config.exists();
}
}