package com.anjlab.eclipse.tapestry5;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJarEntryResource;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.anjlab.eclipse.tapestry5.templates.ProjectSettings;
@SuppressWarnings("restriction")
public class TapestryUtils
{
public static final String SRC_MAIN_ECLIPSE_TAPESTRY5 = "src/main/eclipse-tapestry5";
private static final String TAPESTRY_APP_PACKAGE = "tapestry.app-package";
public static String getPagesPath(IProject project)
{
String appPackage = getAppPackage(project);
return appPackage != null
? '/' + appPackage.replace('.', '/') + "/pages"
: "";
}
public static String getComponentsPath(IProject project)
{
String appPackage = getAppPackage(project);
return appPackage != null
? '/' + appPackage.replace('.', '/') + "/components"
: "";
}
public static String getMixinsPath(IProject project)
{
String appPackage = getAppPackage(project);
return appPackage != null
? '/' + appPackage.replace('.', '/') + "/mixins"
: "";
}
public static String joinPath(String part1, String part2)
{
return (part1 + '/' + part2).replaceAll("//", "/");
}
public static String getRelativeFileName(IResource resource, IContainer ancestor)
{
return resource.getProjectRelativePath().toPortableString().substring(
ancestor.getProjectRelativePath().toPortableString().length());
}
public static String getPagesPackage(IProject project)
{
return getTapestryPackage(project, "pages");
}
public static String getTapestryPackage(IProject project, String subpackage)
{
String appPackage = getAppPackage(project);
return appPackage != null
? appPackage + "." + subpackage
: null;
}
public static String getComponentsPackage(IProject project)
{
return getTapestryPackage(project, "components");
}
public static String getMixinsPackage(IProject project)
{
return getTapestryPackage(project, "mixins");
}
public static boolean isStyleSheetFile(IPath path)
{
return "css".equals(path.getFileExtension());
}
public static boolean isJavaScriptFile(IPath file)
{
return "js".equals(file.getFileExtension());
}
public static boolean isTemplateFile(IPath path)
{
return "tml".equals(path.getFileExtension());
}
public static boolean isClassFile(IPath path)
{
return "class".equals(path.getFileExtension());
}
public static boolean isJavaFile(IPath path)
{
return "java".equals(path.getFileExtension());
}
public static boolean isPropertiesFile(IPath path)
{
return "properties".equals(path.getFileExtension());
}
public static AssetResolver createAssetResolver(String bindingPrefix) throws UnresolvableReferenceException
{
if ("classpath".equals(bindingPrefix))
{
return new ClasspathAssetResolver2();
}
else if ("context".equals(bindingPrefix))
{
return new ContextAssetResolver();
}
throw new UnresolvableReferenceException("Binding prefix '" + bindingPrefix + "' not supported");
}
public static IContainer findWebapp(IProject project)
{
// TODO Support non-default locations?
return (IContainer) project.findMember("src/main/webapp");
}
public static IFile findWebXml(IProject project)
{
IContainer webapp = TapestryUtils.findWebapp(project);
if (webapp == null)
{
return null;
}
return (IFile) webapp.findMember("/WEB-INF/web.xml");
}
public static boolean isTapestryProject(IProject project)
{
return getAppPackage(project) != null;
}
public static String getAppPackage(IProject project)
{
return Activator.getDefault().getWebXml(project).getParamValue(TAPESTRY_APP_PACKAGE);
}
public static boolean isTapestryJavaScriptStackInterface(String interfaceName)
{
return "JavaScriptStack".equals(interfaceName)
|| "org.apache.tapestry5.services.javascript.JavaScriptStack".equals(interfaceName);
}
public static String getSimpleName(String className)
{
int lastDot = className.lastIndexOf('.');
if (lastDot != -1)
{
return className.substring(lastDot + 1);
}
return className;
}
public static boolean isAnnotationEquals(Annotation annotation, String typeName)
{
return isTypeNameEquals(annotation.getTypeName().getFullyQualifiedName(), typeName);
}
private static boolean isTypeNameEquals(String name, String fqName)
{
return name.equals(fqName) || name.equals(getSimpleName(fqName));
}
public static IAnnotation findAnnotation(IAnnotation[] annotations, String typeName)
{
for (IAnnotation annotation : annotations)
{
if (isTypeNameEquals(annotation.getElementName(), typeName))
{
return annotation;
}
}
return null;
}
public static boolean isTapestryImportAnnotation(Annotation annotation)
{
String name = annotation.getTypeName().getFullyQualifiedName();
return "org.apache.tapestry5.annotations.Import".equals(name) || "Import".equals(name);
}
public static TapestryContext createTapestryContext(IWorkbenchWindow window)
{
TapestryFile file = getTapestryFileFromSelection(window.getSelectionService().getSelection());
if (file != null)
{
return file.getContext();
}
file = TapestryUtils.getTapestryFileFromPage(window.getActivePage());
if (file != null)
{
return file.getContext();
}
file = getTapestryFileFromSelection(EclipseUtils.getProjectExplorerSelection(window));
if (file != null)
{
return file.getContext();
}
return TapestryContext.emptyContext();
}
public static IContainer getRoot(IContainer forContainer)
{
if (forContainer == null)
{
return null;
}
final IContainer webapp = findWebapp(forContainer.getProject());
RootDetector rootDetector = new RootDetector()
{
@Override
public boolean isRoot(IContainer container)
{
try
{
return EclipseUtils.isSourceFolder(container) || container.equals(webapp);
}
catch (JavaModelException e)
{
return false;
}
}
};
return getRoot(forContainer, rootDetector);
}
public static IContainer getRoot(IFile forFile)
{
if (forFile == null)
{
return null;
}
return getRoot(forFile.getParent());
}
private static interface RootDetector
{
boolean isRoot(IContainer container);
}
private static IContainer getRoot(IContainer forContainer, RootDetector rootDetector)
{
if (forContainer == null)
{
return null;
}
IContainer container = forContainer;
while (container != null && !rootDetector.isRoot(container))
{
container = container.getParent();
}
return container;
}
public static boolean isWebApp(IContainer root)
{
return root.equals(findWebapp(root.getProject()));
}
public static String pathToPackageName(String relativeFileName, boolean leadingDot)
{
return (!leadingDot && relativeFileName.startsWith("/")
? relativeFileName.substring(1)
: relativeFileName)
.replaceAll("/", ".");
}
public static String readToEnd(InputStream stream)
{
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
try
{
StringBuilder builder = new StringBuilder();
int ch;
while ((ch = reader.read()) != -1)
{
builder.append((char) ch);
}
return builder.toString();
}
catch (IOException e)
{
Activator.getDefault().logError("Error reading stream", e);
}
finally
{
try
{
reader.close();
}
catch (IOException e)
{
// Ignore
}
}
return null;
}
public static TapestryFile getTapestryFileFromPage(IWorkbenchPage page)
{
if (page == null)
{
return null;
}
IEditorPart activeEditor = page.getActiveEditor();
if (activeEditor == null)
{
return null;
}
IEditorInput editorInput = activeEditor.getEditorInput();
if (editorInput instanceof IFileEditorInput)
{
IFileEditorInput fileEditorInput = (IFileEditorInput) editorInput;
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext(fileEditorInput.getFile())
.getInitialFile();
}
if (editorInput instanceof IStorageEditorInput)
{
try
{
IStorage storage = ((IStorageEditorInput) editorInput).getStorage();
if (storage instanceof IJarEntryResource)
{
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext((IJarEntryResource) storage)
.getInitialFile();
}
}
catch (CoreException e)
{
// Ignore
Activator.getDefault().logError("Error getting file from JAR", e);
}
}
if (editorInput instanceof IClassFileEditorInput)
{
IClassFile classFile = ((IClassFileEditorInput) editorInput).getClassFile();
if (classFile != null)
{
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext(classFile)
.getInitialFile();
}
}
return null;
}
private static TapestryFile getTapestryFileFromSelectionElement(Object firstElement) throws JavaModelException
{
if (firstElement == null)
{
return null;
}
if (firstElement instanceof ICompilationUnit)
{
ICompilationUnit compilationUnit = ((ICompilationUnit) firstElement);
TapestryFile file = TapestryUtils.getFileFromResource(compilationUnit.getCorrespondingResource());
if (file != null)
{
return file;
}
}
if (firstElement instanceof IClassFile)
{
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext((IClassFile) firstElement)
.getInitialFile();
}
if (firstElement instanceof IJarEntryResource)
{
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext((IJarEntryResource) firstElement)
.getInitialFile();
}
if (firstElement instanceof ITreeSelection)
{
ITreeSelection treeSelection = (ITreeSelection) firstElement;
return getTapestryFileFromSelectionElement(treeSelection.getFirstElement());
}
IResource resource = (IResource) Platform.getAdapterManager().getAdapter(firstElement, IResource.class);
if (resource != null)
{
TapestryFile file = TapestryUtils.getFileFromResource(resource);
if (file != null)
{
return file;
}
}
return null;
}
public static TapestryModule getTapestryModule(IWorkbenchWindow window, IProject project)
{
if (project != null)
{
TapestryProject tapestryProject = Activator.getDefault().getTapestryProject(window);
if (tapestryProject != null)
{
for (TapestryModule module : tapestryProject.modules())
{
if (project.equals(
module.getModuleClass().getJavaProject().getProject()))
{
return module;
}
}
}
}
return null;
}
public static TapestryFile getTapestryFileFromSelection(ISelection selection)
{
try
{
return selection instanceof IStructuredSelection
? getTapestryFileFromSelectionElement(((IStructuredSelection) selection).getFirstElement())
: null;
}
catch (JavaModelException e)
{
// Ignore
return null;
}
}
protected static TapestryFile getFileFromResource(IResource resource)
{
if (resource != null)
{
IFile file = (IFile) resource.getAdapter(IFile.class);
if (file != null)
{
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext(file)
.getInitialFile();
}
}
return null;
}
public static TapestryContextScope getTapestryContext(IWorkbenchWindow window, String componentName)
{
TapestryContext tapestryContext = Activator.getDefault().getTapestryContext(window);
if (tapestryContext == null)
{
return null;
}
TapestryModule tapestryModule = getTapestryModule(window, tapestryContext.getProject());
if (tapestryModule == null)
{
return null;
}
TapestryContext targetContext;
try
{
targetContext = tapestryModule.getProject().findComponentContext(componentName);
}
catch (JavaModelException e)
{
return null;
}
if (targetContext == null)
{
return null;
}
return new TapestryContextScope(window, tapestryModule.getProject(), targetContext, null);
}
public static TapestryFile findFileInSourceFolders(IJavaProject javaProject, String path)
{
try
{
for (IPackageFragmentRoot root : javaProject.getAllPackageFragmentRoots())
{
if (!EclipseUtils.isSourceFolder(root))
{
continue;
}
IContainer container = (IContainer) root.getCorrespondingResource().getAdapter(IContainer.class);
IFile file = EclipseUtils.findFileCaseInsensitive(container, path);
if (file != null)
{
return Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext(file)
.getInitialFile();
}
}
}
catch (JavaModelException e)
{
// Ignore
}
return null;
}
public static String getDefaultContextNameFromFileName(String fileNameWithoutExtension)
{
final String DEFAULT_CONTEXT_NAME = "Unknown";
if (StringUtils.isEmpty(fileNameWithoutExtension))
{
return DEFAULT_CONTEXT_NAME;
}
StringBuilder builder = new StringBuilder(fileNameWithoutExtension.length());
boolean changeCase = true;
for (int i = 0; i < fileNameWithoutExtension.length(); i++)
{
char ch = fileNameWithoutExtension.charAt(i);
if (Character.isDigit(ch) || Character.isLetter(ch))
{
if (changeCase)
{
ch = Character.toUpperCase(ch);
changeCase = Character.isDigit(ch);
}
builder.append(ch);
}
else
{
changeCase = true;
}
}
return builder.length() == 0
? DEFAULT_CONTEXT_NAME
: builder.toString();
}
public static JavaScriptStack findStack(IProject project, String stackName)
{
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
for (IWorkbenchWindow window : windows)
{
TapestryProject tapestryProject = Activator.getDefault().getTapestryProject(window);
if (tapestryProject != null && tapestryProject.contains(project))
{
return tapestryProject.findStack(stackName);
}
}
return null;
}
public static boolean isTapestryDefaultNamespace(String namespace)
{
return !StringUtils.isEmpty(namespace)
&& namespace.startsWith("http://tapestry.apache.org/schema/tapestry");
}
public static String findTapestryAttribute(Node node, String attributeName)
{
NamedNodeMap attributes = node.getAttributes();
for (int i = 0; i < attributes.getLength(); i++)
{
Node attribute = attributes.item(i);
if (attribute.getNamespaceURI() != null && isTapestryDefaultNamespace(attribute.getNamespaceURI()))
{
if (attributeName.equals(attribute.getLocalName()))
{
return attribute.getNodeValue();
}
}
}
return null;
}
public static String getComponentName(IWorkbenchWindow window, Node element)
{
// if element is from Tapestry namespace -- we have a componentName
String namespace = element.getNamespaceURI();
if (namespace != null)
{
if (isTapestryDefaultNamespace(namespace))
{
return element.getLocalName();
}
else if (namespace.startsWith("tapestry-library:"))
{
return namespace.substring("tapestry-library:".length()) + "." + element.getLocalName();
}
else if (namespace.equals("tapestry:parameter"))
{
// TODO Add support for tapestry parameters
return null;
}
}
String componentName = findTapestryAttribute(element, "type");
if (componentName == null)
{
String componentId = findTapestryAttribute(element, "id");
if (componentId != null)
{
// Get type from field declaration in Java class
TapestryContext tapestryContext = Activator.getDefault().getTapestryContext(window);
if (tapestryContext == null)
{
return null;
}
TapestryProject tapestryProject = Activator.getDefault().getTapestryProject(window);
for (Component component : tapestryContext.getSpecification().getComponents())
{
if (StringUtils.equals(componentId, component.getId()))
{
return getComponentName(tapestryProject, component);
}
}
}
}
return componentName;
}
public static String getComponentName(TapestryProject tapestryProject, Component component)
{
if (component.isJavaType())
{
// Convert component type to component name
for (TapestryModule tapestryModule : tapestryProject.modules())
{
for (LibraryMapping libraryMapping : tapestryModule.libraryMappings())
{
if (component.getType().startsWith(libraryMapping.getRootPackage()))
{
return component.getType().substring(
(libraryMapping.getRootPackage() + ".components").length()
+ ".".length());
}
}
}
return null;
}
return component.getType();
}
public static boolean isTapestryComponentsNamespace(String namespace)
{
if (StringUtils.isEmpty(namespace))
{
return false;
}
return isTapestryDefaultNamespace(namespace)
|| namespace.startsWith("tapestry-library:");
}
public static final String ORG_APACHE_TAPESTRY5_ANNOTATIONS_PATH = "org.apache.tapestry5.annotations.Path";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_SUB_MODULE = "org.apache.tapestry5.ioc.annotations.SubModule";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_IMPORT_MODULE = "org.apache.tapestry5.ioc.annotations.ImportModule";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_ADVISE = "org.apache.tapestry5.ioc.annotations.Advise";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_SERVICE_ID = "org.apache.tapestry5.ioc.annotations.ServiceId";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_CONTRIBUTE = "org.apache.tapestry5.ioc.annotations.Contribute";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_STARTUP = "org.apache.tapestry5.ioc.annotations.Startup";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_DECORATE = "org.apache.tapestry5.ioc.annotations.Decorate";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_ORDER = "org.apache.tapestry5.ioc.annotations.Order";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_MATCH = "org.apache.tapestry5.ioc.annotations.Match";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_OPTIONAL = "org.apache.tapestry5.ioc.annotations.Optional";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_MARKER = "org.apache.tapestry5.ioc.annotations.Marker";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_SYMBOL = "org.apache.tapestry5.ioc.annotations.Symbol";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_INJECT = "org.apache.tapestry5.ioc.annotations.Inject";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_INJECT_SERVICE = "org.apache.tapestry5.ioc.annotations.InjectService";
public static final String ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_LOCAL = "org.apache.tapestry5.ioc.annotations.Local";
public static final String JAVAX_INJECT_NAMED = "javax.inject.Named";
public static final String BUILD_METHOD_NAME_PREFIX = "build";
public static final String CONTRIBUTE_METHOD_NAME_PREFIX = "contribute";
public static final String ADVISE_METHOD_NAME_PREFIX = "advise";
public static final String DECORATE_METHOD_NAME_PREFIX = "decorate";
public static boolean isStartupMethod(IMethod method) throws JavaModelException
{
return method.getElementName().equals("startup")
|| findAnnotation(
method.getAnnotations(),
ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_STARTUP) != null;
}
public static boolean isContributorMethod(IMethod method) throws JavaModelException
{
return method.getElementName().startsWith(CONTRIBUTE_METHOD_NAME_PREFIX)
|| findAnnotation(
method.getAnnotations(),
ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_CONTRIBUTE) != null;
}
public static boolean isAdvisorMethod(IMethod method) throws JavaModelException
{
return method.getElementName().startsWith(ADVISE_METHOD_NAME_PREFIX)
|| findAnnotation(
method.getAnnotations(),
ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_ADVISE) != null;
}
public static boolean isDecoratorMethod(IMethod method) throws JavaModelException
{
return method.getElementName().startsWith(DECORATE_METHOD_NAME_PREFIX)
|| findAnnotation(
method.getAnnotations(),
ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_DECORATE) != null;
}
public static boolean isServiceBuilderMethod(IMethod method)
{
return method.getElementName().startsWith(BUILD_METHOD_NAME_PREFIX);
}
public static TapestryProject getCurrentProject()
{
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
TapestryProject tapestryProject = Activator.getDefault().getTapestryProject(window);
return tapestryProject;
}
public static String expandSymbols(String input)
{
TapestryProject project = getCurrentProject();
if (project != null)
{
try
{
input = project.expandSymbols(input);
}
catch (RuntimeException e)
{
Activator.getDefault().logWarning(
"Error expanding asset '" + input + "'", e);
}
}
return input;
}
public static boolean isModuleFile(IFile affectedFile, TapestryModule module)
{
return ObjectUtils.equals(module.getModuleFile().getPath(), affectedFile.getProjectRelativePath())
&& ObjectUtils.equals(module.getModuleFile().getProject(), affectedFile.getProject());
}
public static ProjectSettings readProjectSettings(TapestryProject tapestryProject)
{
ProjectSettings defaultSettings = ProjectSettings.getDefault(tapestryProject);
if (tapestryProject == null)
{
return defaultSettings;
}
IContainer configDir =
(IContainer) tapestryProject.getProject()
.findMember(SRC_MAIN_ECLIPSE_TAPESTRY5);
if (configDir == null)
{
return defaultSettings;
}
IFile file = (IFile) configDir.findMember(ProjectSettings.CONFIG_FILE_NAME);
if (file == null)
{
return defaultSettings;
}
try
{
InputStream input = file.getContents();
try
{
ProjectSettings projectSettings = defaultSettings.extend(ProjectSettings.parse(input));
projectSettings.setSource(file);
return projectSettings;
}
finally
{
input.close();
}
}
catch (Exception e)
{
Activator.getDefault().logError("Error parsing " + file.getProjectRelativePath(), e);
return defaultSettings;
}
}
// From http://stackoverflow.com/a/1248627/2414933
public static String createRegexpFromGlob(String line)
{
String out = "^";
for(int i = 0; i < line.length(); ++i)
{
final char c = line.charAt(i);
switch(c)
{
case '*': out += ".*"; break;
case '?': out += '.'; break;
case '.': out += "\\."; break;
case '\\': out += "\\\\"; break;
default: out += c;
}
}
out += '$';
return out;
}
}