package com.anjlab.eclipse.tapestry5.views.context; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.core.resources.IProject; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.ui.IWorkbenchWindow; import com.anjlab.eclipse.tapestry5.Activator; import com.anjlab.eclipse.tapestry5.ClassNameReference; import com.anjlab.eclipse.tapestry5.TapestryContext; import com.anjlab.eclipse.tapestry5.TapestryFile; import com.anjlab.eclipse.tapestry5.TapestryModule; import com.anjlab.eclipse.tapestry5.TapestryProject; import com.anjlab.eclipse.tapestry5.TapestryService; import com.anjlab.eclipse.tapestry5.TapestryService.ServiceDefinition; import com.anjlab.eclipse.tapestry5.TapestryService.ServiceInstrumenter; import com.anjlab.eclipse.tapestry5.internal.ServiceImplMatcher; import com.anjlab.eclipse.tapestry5.internal.ServiceIntfMatcher; import com.anjlab.eclipse.tapestry5.views.IProjectProvider; import com.anjlab.eclipse.tapestry5.views.TreeObject; import com.anjlab.eclipse.tapestry5.views.TreeParent; import com.anjlab.eclipse.tapestry5.views.TreeParent.DataObject; import com.anjlab.eclipse.tapestry5.views.project.TapestryProjectOutlineContentProvider; public class TapestryContextContentProvider implements ITreeContentProvider, IProjectProvider { private static final Object[] NO_CHILDREN = new Object[0]; private final IWorkbenchWindow window; private final TapestryContext context; private TreeParent invisibleRoot; public TapestryContextContentProvider(IWorkbenchWindow window, TapestryContext context) { this.window = window; this.context = context; } @Override public IProject getProject() { return context == null ? null : context.getProject(); } private void initialize() { invisibleRoot = new TreeParent("", new Object()); if (context != null && !context.isEmpty()) { TapestryModule module = getTapestryModule(context); if (module != null) { TreeParent moduleRoot = new TreeParent(module.getName(), module); TapestryProjectOutlineContentProvider.buildModuleTree(module, moduleRoot); invisibleRoot.addChild(moduleRoot); return; } TapestryService serviceImpl = getTapestryServiceImpl(context); if (serviceImpl != null) { TreeParent serviceImplRoot = new TreeParent( context.getInitialFile().getName(), context.getInitialFile()); buildServiceImplTree(serviceImpl, serviceImplRoot); invisibleRoot.addChild(serviceImplRoot); return; } TapestryService serviceIntf = getTapestryServiceIntf(context); if (serviceIntf != null) { TreeParent serviceIntfRoot = new TreeParent( context.getInitialFile().getName(), context.getInitialFile()); buildServiceIntfTree(serviceIntf, serviceIntfRoot); invisibleRoot.addChild(serviceIntfRoot); return; } for (TapestryFile relatedFile : context.getFiles()) { invisibleRoot.addChild(new TreeObject(relatedFile.getName(), relatedFile)); } } } private void buildServiceImplTree(TapestryService service, TreeParent serviceRoot) { TapestryProject project = Activator.getDefault().getTapestryProject(window); if (project == null) { return; } // TODO Data objects should only be equals for exactly same item across all tree views // i.e. data for same-named TreeParents for different nodes must be different // otherwise Eclipse will reuse those items TreeParent otherImplsRoot = new TreeParent("Other Implementations", new DataObject("Other Implementations")); ServiceIntfMatcher intfMatcher = new ServiceIntfMatcher(service.getDefinition().getIntfClass()); for (TapestryModule module : project.modules()) { for (TapestryService other : module.services()) { if (service != other && intfMatcher.matches(other)) { otherImplsRoot.addChild( new TreeObject( other.getDefinition().getId(), new ClassNameReference( getProject(), other.getDefinition().getImplClass()))); } } } addIfHasChildren(serviceRoot, otherImplsRoot); TreeParent specificationRoot = buildSpecificationTree(service, serviceRoot); TapestryService serviceIntf = project.findService( new ServiceIntfMatcher(service.getDefinition().getIntfClass())); if (serviceIntf != null) { addInstrumenters(serviceRoot, project, serviceIntf); } else { addNotInstrumentingNotice(specificationRoot); } } private TreeParent buildSpecificationTree(TapestryService service, TreeParent serviceRoot) { ServiceDefinition definition = service.getDefinition(); TreeParent specificationRoot = new TreeParent("Specification", new DataObject("Specification")); serviceRoot.addChild(specificationRoot); specificationRoot.addChild(new TreeObject("Defined in", service.getReference())); specificationRoot.addChild(new TreeObject("Id", ObjectUtils.defaultIfNull(definition.getId(), "<?>"))); specificationRoot.addChild(new TreeObject("Intf", definition.getIntfClass() != null ? new ClassNameReference(getProject(), definition.getIntfClass()) : "<?>")); specificationRoot.addChild(new TreeObject("Scope", ObjectUtils.defaultIfNull(definition.getScope(), "Singleton"))); TreeParent markersRoot = new TreeParent("Markers", new DataObject("Markers")); for (String marker : definition.getMarkers()) { markersRoot.addChild(new TreeObject(marker, new DataObject(marker))); } addIfHasChildren(specificationRoot, markersRoot); return specificationRoot; } private void addNotInstrumentingNotice(TreeParent specificationRoot) { String notInstumentingNotice = "Instrumentation & scope won't be applied"; specificationRoot.addChild( new TreeObject( "*", notInstumentingNotice)); } private void addInstrumenters(TreeParent serviceRoot, TapestryProject project, TapestryService serviceIntf) { TreeParent advisorsRoot = new TreeParent("Advisors", new DataObject("Advisors")); for (TapestryModule module : project.modules()) { for (ServiceInstrumenter advisor : module.advisors()) { if (advisor.getServiceMatcher().matches(serviceIntf)) { advisorsRoot.addChild(new TreeObject(StringUtils.defaultIfEmpty(advisor.getId(), "<?>"), advisor)); } } } addIfHasChildren(serviceRoot, advisorsRoot); TreeParent decoratorsRoot = new TreeParent("Decorators", new DataObject("Decorators")); for (TapestryModule module : project.modules()) { for (ServiceInstrumenter decorator : module.decorators()) { if (decorator.getServiceMatcher().matches(serviceIntf)) { decoratorsRoot.addChild(new TreeObject(StringUtils.defaultIfEmpty(decorator.getId(), "<?>"), decorator)); } } } addIfHasChildren(serviceRoot, decoratorsRoot); TreeParent contributorsRoot = new TreeParent("Contributors", new DataObject("Contributors")); for (TapestryModule module : project.modules()) { for (ServiceInstrumenter contributor : module.contributors()) { if (contributor.getServiceMatcher().matches(serviceIntf)) { contributorsRoot.addChild(new TreeObject(StringUtils.defaultIfEmpty(contributor.getId(), "<?>"), contributor)); } } } addIfHasChildren(serviceRoot, contributorsRoot); } private void buildServiceIntfTree(TapestryService service, TreeParent serviceRoot) { TapestryProject project = Activator.getDefault().getTapestryProject(window); if (project == null) { return; } buildSpecificationTree(service, serviceRoot); TreeParent otherImplsRoot = new TreeParent("Implementations", new DataObject("Implementations")); ServiceIntfMatcher intfMatcher = new ServiceIntfMatcher(service.getDefinition().getIntfClass()); for (TapestryModule module : project.modules()) { for (TapestryService other : module.services()) { if (intfMatcher.matches(other)) { otherImplsRoot.addChild( new TreeObject( other.getDefinition().getId(), new ClassNameReference( getProject(), other.getDefinition().getImplClass()))); } } } addIfHasChildren(serviceRoot, otherImplsRoot); addInstrumenters(serviceRoot, project, service); } private TapestryService getTapestryServiceImpl(TapestryContext context) { TapestryProject project = Activator.getDefault().getTapestryProject(window); if (project == null) { return null; } TapestryFile file = context.getInitialFile(); if (!file.isJavaFile()) { return null; } String className = file.getClassName(); if (StringUtils.isEmpty(className)) { return null; } return project.findService(new ServiceImplMatcher(className)); } private TapestryService getTapestryServiceIntf(TapestryContext context) { TapestryProject project = Activator.getDefault().getTapestryProject(window); if (project == null) { return null; } TapestryFile file = context.getInitialFile(); if (!file.isJavaFile()) { return null; } String className = file.getClassName(); if (StringUtils.isEmpty(className)) { return null; } return project.findService(new ServiceIntfMatcher(className)); } /** * * @param context * @return * if this context represents tapestry module then that module will be returned, * otherwise null. */ private TapestryModule getTapestryModule(TapestryContext context) { TapestryProject project = Activator.getDefault().getTapestryProject(window); if (project == null) { return null; } for (TapestryModule module : project.modules()) { if (module.getModuleFile().equals(context.getInitialFile())) { return module; } } return null; } public TapestryContext getContext() { return context; } public Object[] getElements(Object parent) { if (parent instanceof TapestryContextView || parent instanceof IInformationControl) { if (invisibleRoot == null) { initialize(); } return getChildren(invisibleRoot); } return NO_CHILDREN; } public Object getParent(Object child) { if (child instanceof TreeObject) { return ((TreeObject) child).getParent(); } return null; } public Object[] getChildren(Object parent) { if (parent instanceof TreeParent) { return ((TreeParent) parent).getChildren(); } return NO_CHILDREN; } public boolean hasChildren(Object parent) { if (parent instanceof TreeParent) { return ((TreeParent) parent).hasChildren(); } return false; } public boolean hasElements() { return getElements(null).length > 0; } public void inputChanged(Viewer v, Object oldInput, Object newInput) { } public void dispose() { } private static void addIfHasChildren(TreeParent root, TreeParent child) { if (child.hasChildren()) { root.addChild(child); } } }