/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.sling.ide.eclipse.ui.nav.model; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.jcr.PropertyType; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.PropertyDefinition; import javax.xml.parsers.ParserConfigurationException; import org.apache.jackrabbit.util.ISO9075; import org.apache.sling.ide.eclipse.core.ProjectUtil; import org.apache.sling.ide.eclipse.core.ServerUtil; import org.apache.sling.ide.eclipse.core.internal.Activator; import org.apache.sling.ide.eclipse.ui.WhitelabelSupport; import org.apache.sling.ide.eclipse.ui.views.PropertyTypeSupport; import org.apache.sling.ide.filter.Filter; import org.apache.sling.ide.filter.FilterResult; import org.apache.sling.ide.log.Logger; import org.apache.sling.ide.serialization.SerializationKind; import org.apache.sling.ide.serialization.SerializationKindManager; import org.apache.sling.ide.serialization.SerializationManager; import org.apache.sling.ide.transport.NodeTypeRegistry; import org.apache.sling.ide.transport.Repository; import org.apache.sling.ide.transport.RepositoryException; import org.apache.sling.ide.transport.ResourceProxy; import org.eclipse.core.resources.IContainer; 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.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.resources.mapping.ResourceMappingContext; import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IActionFilter; import org.eclipse.ui.IContributorResourceAdapter; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.CopyFilesAndFoldersOperation; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.part.ResourceTransfer; import org.eclipse.ui.views.properties.IPropertySource; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; import org.xml.sax.SAXException; import de.pdark.decentxml.Attribute; import de.pdark.decentxml.Document; import de.pdark.decentxml.Element; import de.pdark.decentxml.Namespace; import de.pdark.decentxml.Node; import de.pdark.decentxml.Text; import de.pdark.decentxml.XMLParseException; import de.pdark.decentxml.XMLTokenizer.Type; /** WIP: model object for a jcr node shown in the content package view in project explorer **/ public class JcrNode implements IAdaptable { private final static WorkbenchLabelProvider workbenchLabelProvider = new WorkbenchLabelProvider(); final GenericJcrRootFile underlying; JcrNode parent; DirNode dirSibling; final List<JcrNode> children = new LinkedList<>(); Element domElement; private IResource resource; private boolean resourceChildrenAdded = false; final ModifiableProperties properties = new ModifiableProperties(this); final Set<JcrNode> hiddenChildren = new HashSet<>(); JcrNode() { // for subclass use only if (this instanceof GenericJcrRootFile) { this.underlying = (GenericJcrRootFile) this; } else { this.underlying = null; } } JcrNode(JcrNode parent, Element domElement, IResource resource) { this(parent, domElement, parent.underlying, resource); } JcrNode(JcrNode parent, Element domElement, GenericJcrRootFile underlying, IResource resource) { if (parent == null) { throw new IllegalArgumentException("parent must not be null"); } this.parent = parent; // domElement can be null this.domElement = domElement; this.underlying = underlying; this.resource = resource; parent.addChild(this); } @Override public String toString() { return getClass().getSimpleName() + "[dom:"+domElement+", file:"+resource+", jcrPath:"+getJcrPath()+"]"; } @Override public int hashCode() { if (underlying==null) { if (resource==null) { if (domElement==null) { return toString().hashCode(); } else { Element domElementCopy = domElement.copy(); domElementCopy.clearChildren(); return domElementCopy.toString().hashCode() + parent.hashCode(); } } else { return resource.getFullPath().hashCode(); } } else { if (domElement==null) { return underlying.hashCode(); } Element domElementCopy = domElement.copy(); domElementCopy.clearChildren(); return underlying.hashCode() + domElementCopy.toString().hashCode(); } } @Override public boolean equals(Object obj) { if (this==obj) { return true; } if (!(obj instanceof JcrNode)) { return false; } JcrNode other = (JcrNode) obj; if (resource!=null && other.resource!=null) { if (resource.equals(other.resource)) { return true; } else { return false; } } else if (resource!=null && other.resource==null) { return false; } else if (resource==null && other.resource!=null) { return false; } if (other.underlying==null && underlying!=null) { return false; } else if (other.underlying!=null && underlying==null) { return false; } if (underlying!=null && !underlying.equals(other.underlying)) { return false; } if (parent!=null && other.parent!=null) { if (!parent.equals(other.parent)) { return false; } Element domElementCopy = domElement.copy(); domElementCopy.clearChildren(); Element otherDomElementCopy = other.domElement.copy(); otherDomElementCopy.clearChildren(); return domElementCopy.toString().equals(otherDomElementCopy.toString()); } return toString().equals(obj.toString()); } protected void addChild(JcrNode jcrNode) { if (!children.contains(jcrNode)) { // check to see if there is a same-named node though // that is the dom/resource case for (JcrNode existingChild : children) { if (existingChild.getName().equals(jcrNode.getName())) { // then merge the two existingChild.setResource(jcrNode.resource); return; } } children.add(jcrNode); } } /** shown in the navigator (project explorer) as the label of this element **/ public String getLabel() { if (domElement!=null && resource!=null) { return ISO9075.decode(getDomName());// + "[domnode+file]"; } else if (domElement!=null && resource==null) { return ISO9075.decode(getDomName());// + "[domnode]"; } else if (resource!=null) { return resource.getName();//+" [file]"; } else { return "n/a"; } } /** shown in the statusbar when this element is selected **/ public String getDescription() { return getJcrPath(); } public boolean hasChildren() { boolean members; try { members = resource!=null && resource instanceof IFolder && ((IFolder)resource).members().length>0; } catch (CoreException e) { members = false; } return children.size()>0 || members; } public void hide(JcrNode node) { hiddenChildren.add(node); } Object[] filterHiddenChildren(final Collection<JcrNode> collection, boolean hideEmptyNodes) { final Collection<JcrNode> values = new LinkedList<>(collection); for (JcrNode hiddenNode : hiddenChildren) { values.remove(hiddenNode); } if (hideEmptyNodes) { for (Iterator<JcrNode> it = values.iterator(); it.hasNext();) { JcrNode jcrNode = it.next(); if (jcrNode.isEmptyNode()) { it.remove(); } } } for (Iterator<JcrNode> it = values.iterator(); it.hasNext();) { JcrNode jcrNode = it.next(); if (jcrNode instanceof DirNode) { DirNode dirNode = (DirNode)jcrNode; // DirNodes are candidates for hiding JcrNode effectiveSibling = dirNode.getEffectiveSibling(); if (effectiveSibling!=null) { it.remove(); continue; } } } return values.toArray(); } private boolean isEmptyNode() { if (resource!=null) { return false; } if (children.size()!=0) { return false; } if (domElement==null) { return true; } if (domElement.hasChildren()) { return false; } if (domElement.getAttributes().size()!=0) { return false; } return true; } public Object[] getChildren(boolean hideEmptyNodes) { if (!resourceChildrenAdded) { initChildren(); } return filterHiddenChildren(children, true); } void initChildren() { try { if (resourceChildrenAdded) { throw new IllegalStateException("Children already loaded"); } Set<String> childrenNames = new HashSet<>(); for (Iterator<JcrNode> it = children.iterator(); it.hasNext();) { JcrNode node = it.next(); childrenNames.add(node.getName()); } if (resource!=null && resource instanceof IFolder) { IFolder folder = (IFolder)resource; IResource[] members = folder.members(); List<IResource> membersList = new LinkedList<>(Arrays.asList(members)); outerLoop: while(membersList.size()>0) { for (Iterator<IResource> it = membersList.iterator(); it.hasNext();) { IResource iResource = it.next(); if (isDotVltFile(iResource)) { it.remove(); continue; } if (childShouldNotBeShown(iResource)) { it.remove(); continue; } if (isVaultFile(iResource)) { GenericJcrRootFile gjrf; try { gjrf = new GenericJcrRootFile(this, (IFile)iResource); it.remove(); // gjrf.getChildren(); gjrf.pickResources(membersList); } catch (XMLParseException e) { // don't try to parse it // errors will be reported by the XML validation infrastructure it.remove(); } // as this might have added some new children, go through the children again and // add them if they're not already added for (JcrNode node : children) { if (!childrenNames.contains(node.getName())) { childrenNames.add(node.getName()); } } continue outerLoop; } } List<JcrNode> newNodes = new LinkedList<>(); for (Iterator<IResource> it = membersList.iterator(); it.hasNext();) { IResource iResource = (IResource) it.next(); JcrNode node; if (DirNode.isDirNode(iResource)) { node = new DirNode(this, (Element)null, iResource); } else { node = new JcrNode(this, (Element)null, iResource); } childrenNames.add(node.getName()); newNodes.add(node); it.remove(); } } } resourceChildrenAdded = true; } catch (CoreException e) { e.printStackTrace(); org.apache.sling.ide.eclipse.ui.internal.Activator.getDefault().getPluginLogger().error("Error initializing children: "+e, e); } catch (ParserConfigurationException e) { e.printStackTrace(); org.apache.sling.ide.eclipse.ui.internal.Activator.getDefault().getPluginLogger().error("Error initializing children: "+e, e); } catch (SAXException e) { e.printStackTrace(); org.apache.sling.ide.eclipse.ui.internal.Activator.getDefault().getPluginLogger().error("Error initializing children: "+e, e); } catch (IOException e) { e.printStackTrace(); org.apache.sling.ide.eclipse.ui.internal.Activator.getDefault().getPluginLogger().error("Error initializing children: "+e, e); } } private boolean isDotVltFile(IResource res) { return res.getType() == IResource.FILE && res.getName().equals(".vlt"); } private boolean isVaultFile(IResource iResource) { return Activator.getDefault().getSerializationManager() .isSerializationFile(iResource.getLocation().toOSString()); } protected boolean childShouldNotBeShown(IResource resource) { return false; } public void setResource(IResource resource) { if (this.resource!=null) { if (resource.equals(this.resource)) { return; } throw new IllegalStateException("can only set resource once"); } this.resource = resource; } public Image getImage() { boolean plainFolder = resource!=null && (resource instanceof IFolder); String primaryType = getProperty("jcr:primaryType").getValueAsString(); boolean typeFolder = probablyFolderType(primaryType); boolean typeFile = primaryType!=null && ((primaryType.equals("nt:file") || primaryType.equals("nt:resource") || primaryType.equals("sling:File"))); typeFile |= (resource!=null && primaryType==null); boolean typeUnstructured = primaryType!=null && ((primaryType.equals("nt:unstructured"))); boolean isVaultFile = resource != null && isVaultFile(resource); String mimeType = null; mimeType = getJcrContentProperty("jcr:mimeType"); if (mimeType == null) { mimeType = getProperty("jcr:mimeType").getValueAsString(); } if (typeUnstructured) { return WhitelabelSupport.getJcrNodeIcon().createImage(); } else if (plainFolder || typeFolder) { return workbenchLabelProvider.getImage(ProjectUtil.getSyncDirectory(getProject())); } else if (typeFile && resource!=null) { if (mimeType!=null && mimeType.length()!=0) { ImageDescriptor desc = getImageDescriptor(resource.getName(), mimeType); if (desc!=null) { return desc.createImage(); } } if (isVaultFile) { return WhitelabelSupport.getJcrNodeIcon().createImage(); } return workbenchLabelProvider.getImage(resource); } else { if (resource!=null && !isVaultFile) { return workbenchLabelProvider.getImage(resource); } return WhitelabelSupport.getJcrNodeIcon().createImage(); } } private boolean probablyFolderType(String primaryType) { return primaryType != null && (primaryType.equals("nt:folder") || primaryType.equals("sling:Folder")); } private ImageDescriptor getImageDescriptor(String filename, String jcrMimeType) { final String modifiedFilename; if (jcrMimeType.equals("image/jpeg")) { modifiedFilename = filename + ".jpg"; } else if (jcrMimeType.contains("/")) { modifiedFilename = filename + "." + (jcrMimeType.substring(jcrMimeType.indexOf("/")+1)); } else { return null; } return PlatformUI.getWorkbench().getEditorRegistry().getImageDescriptor(modifiedFilename, null); } private String getJcrContentProperty(String propertyKey) { for (Object element : getChildren(false)) { JcrNode jcrNode = (JcrNode) element; if ("jcr:content".equals(jcrNode.getName())) { return jcrNode.getProperty(propertyKey).getValueAsString(); } } return null; } private String getPropertyAsString(String propertyKey) { if (properties!=null) { Object propertyValue = properties.getValue(propertyKey); if (propertyValue!=null) { return String.valueOf(propertyValue); } } return null; } public String getName() { if (domElement!=null) { return ISO9075.decode(getDomName()); } else if (resource!=null) { return resource.getName(); } else { return ""; } } private String getDomName() { String domName = domElement.getName(); Namespace ns = domElement.getNamespace(); if (ns!=null) { String prefix = ns.getPrefix(); if (!prefix.isEmpty()) { domName = prefix + ":" + domName; } } return domName; } public String getJcrPath() { String prefix; if (parent==null) { prefix = ""; } else { prefix = parent.getJcrPath(); if (!prefix.endsWith("/")) { prefix = prefix + "/"; } } return prefix + getJcrPathName(); } String getJcrPathName() { if (domElement!=null) { return ISO9075.decode(getDomName()); } else if (resource!=null) { if (underlying!=null && resource==underlying.getResource()) { // nodename.xml IResource res = underlying.getResource(); String fullname = res.getName(); if (fullname.endsWith(".xml")) { return fullname.substring(0, fullname.length()-4); } else { return res.getName(); } } else { return resource.getName(); } } else { return ""; } } @Override public Object getAdapter(Class adapter) { return doGetAdapter(adapter); } private Object doGetAdapter(Class adapter) { if (adapter==ITabbedPropertySheetPageContributor.class) { return new ITabbedPropertySheetPageContributor() { @Override public String getContributorId() { return "org.eclipse.ui.navigator.ProjectExplorer"; } }; } else if (adapter==IPropertySource.class) { return null;//properties; } else if (adapter == IFile.class) { if (resource instanceof IFile) { return (IFile)resource; } else { return null; } } else if ( adapter == IFolder.class) { if ( resource instanceof IFolder ) { return (IFolder) resource; } else { return null; } } else if (adapter == IContributorResourceAdapter.class) { //if (resource==null) { // return null; //} return new IContributorResourceAdapter() { @Override public IResource getAdaptedResource(IAdaptable adaptable) { if (!(adaptable instanceof JcrNode)) { return null; } JcrNode node = (JcrNode)adaptable; if (node.resource!=null) { return node.resource; } else { return node.underlying.file; } // return null; } }; } else if (adapter == IResource.class) { if (resource!=null) { return resource; } else { return null;//underlying.file; } } else if (adapter == ResourceMapping.class) { boolean t = true; if (!t) { return null; } // if (resource==null) { // return null; // } return new ResourceMapping() { @Override public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException { if (resource!=null) { return new ResourceTraversal[] { new ResourceTraversal(new IResource[] { resource }, IResource.DEPTH_INFINITE, IResource.NONE) }; } else { return new ResourceTraversal[] { new ResourceTraversal(new IResource[] { underlying.file }, IResource.DEPTH_INFINITE, IResource.NONE) }; } } @Override public IProject[] getProjects() { if (resource!=null) { return new IProject[] {resource.getProject()}; } else { return new IProject[] {underlying.file.getProject()}; } // return null; } @Override public String getModelProviderId() { return "org.apache.sling.ide.eclipse.ui.nav.model.JcrNode.ResourceMapping"; } @Override public Object getModelObject() { if (resource!=null) { return resource; } else { return underlying.file; } } }; } return null; } public ModifiableProperties getProperties() { return properties; } protected boolean isBrowsable() { return true; } public IFile getFileForEditor() { if ("nt:folder".equals(getPrimaryType())) { // nt:folder doesn't have an underlying file for editor return null; } if (resource instanceof IFile) { return (IFile)resource; } if (properties!=null && properties.getUnderlying()!=null && properties.getUnderlying().file!=null) { return properties.getUnderlying().file; } if (underlying!=null && underlying.file!=null) { return underlying.file; } org.apache.sling.ide.eclipse.ui.internal.Activator.getDefault().getPluginLogger().warn("No file found for editor for node="+this); return null; } public IResource getResourceForImportExport() { String path = getJcrPath(); StringTokenizer st = new StringTokenizer(path, "/"); JcrNode root = getParent(); while(true) { JcrNode thisParent = root.getParent(); if (thisParent==null) { break; } root = thisParent; } if (!(root instanceof SyncDir)) { return null; } IFolder folder = ((SyncDir)root).getFolder(); while(st.hasMoreTokens()) { String nodeStr = st.nextToken(); IResource child = folder.findMember(nodeStr); if (child==null || !(child instanceof IFolder)) { break; } else { folder = (IFolder) child; } } return folder; } public void rename(final String string) { if (domElement!=null && underlying!=null) { domElement.setName(string); underlying.save(); } if (resource!=null) { IWorkspaceRunnable r = new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { final IPath fileRenamePath = resource.getParent().getFullPath().append(string); resource.move(fileRenamePath, true, monitor); if (dirSibling!=null) { final IPath dirRenamePath = dirSibling.getResource().getParent().getFullPath().append(string+".dir"); dirSibling.getResource().move(dirRenamePath, true, monitor); } } }; try { ResourcesPlugin.getWorkspace().run(r, null); } catch (CoreException e) { Activator.getDefault().getPluginLogger().error("Error renaming resource ("+resource+"): "+e, e); } } } public boolean canBeRenamed() { if (parent==null) { return false; } if (resource!=null) { // can be a file or a folder (project is virtually impossible) return true; } if (domElement!=null && underlying!=null) { return true; } return false; } public JcrNode getParent() { return parent; } JcrNode getChild(String name) { for (JcrNode child : children) { if (child.getName().equals(name)) { return child; } } return null; } public IResource getResource() { return resource; } private SerializationKind getSerializationKind(String nodeType) { final SerializationKindManager skm = new SerializationKindManager(); final Repository repo = ServerUtil.getDefaultRepository(getProject()); if (repo==null) { return getFallbackSerializationKind(nodeType); } try { skm.init(repo); //TODO: mixins not yet supported return skm.getSerializationKind(nodeType, new ArrayList<String>()); } catch (RepositoryException e) { e.printStackTrace(); return getFallbackSerializationKind(nodeType); } } public void createChild(final String childNodeName, final String childNodeType) { String thisNodeType = getPrimaryType(); final SerializationKind parentSk = getSerializationKind(thisNodeType); final SerializationKind childSk = getSerializationKind(childNodeType); final SerializationManager serializationManager = Activator.getDefault().getSerializationManager(); if (parentSk==SerializationKind.METADATA_FULL) { createDomChild(childNodeName, childNodeType); } else if (parentSk==SerializationKind.FILE) { throw new IllegalStateException("cannot create child of nt:file"); } else if (childSk==SerializationKind.FOLDER) { IWorkspaceRunnable r = new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { IFolder newFolder = prepareCreateFolderChild(childNodeName); if (parentSk==SerializationKind.METADATA_PARTIAL) { // when the parent is partial and we're creating a folder here, // then we're running into a SLING-3639 type of problem // the way around this is to make a 'pointer' in the 'root' // .content.xml, and have a directory structure leaving to // the new node, together with a .content.xml describing // the type (unless it's a nt:folder that is) // 1) 'pointer' in the 'root .content.xml' createDomChild(childNodeName, null); // 2) directory structure is created above already // 3) new .content.xml is done below } if (!childNodeType.equals("nt:folder")) { createVaultFile(newFolder, ".content.xml", childNodeType); } } }; try { ResourcesPlugin.getWorkspace().run(r, null); if (childNodeType.equals("nt:folder") && parentSk==SerializationKind.FOLDER) { // trigger a publish, as folder creation is not propagated to // the SlingLaunchpadBehavior otherwise //TODO: make configurable? Fix in Eclipse/WST? ServerUtil.triggerIncrementalBuild((IFolder)resource, null); } } catch (CoreException e) { Activator.getDefault().getPluginLogger().error("Error creating child "+childNodeName+": "+e, e); e.printStackTrace(); MessageDialog.openError(Display.getDefault().getActiveShell(), "Error creating node", "Error creating child of "+thisNodeType+" with type "+childNodeType+": "+e); return; } } else if ((parentSk == SerializationKind.FOLDER || parentSk == SerializationKind.METADATA_PARTIAL) && childSk == SerializationKind.METADATA_FULL) { createVaultFile((IFolder) resource, serializationManager.getOsPath(childNodeName) + ".xml", childNodeType); } else if (parentSk==SerializationKind.FOLDER && childSk==SerializationKind.METADATA_PARTIAL) { // createVaultFile((IFolder)resource, childNodeName+".xml", childNodeType); IWorkspaceRunnable r = new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { IFolder f = (IFolder)resource; IFolder newFolder = null; newFolder = f.getFolder(serializationManager.getOsPath(childNodeName)); newFolder.create(true, true, new NullProgressMonitor()); createVaultFile(newFolder, ".content.xml", childNodeType); } }; try { ResourcesPlugin.getWorkspace().run(r, null); } catch (CoreException e) { Activator.getDefault().getPluginLogger().error("Error creating child "+childNodeName+": "+e, e); e.printStackTrace(); MessageDialog.openError(Display.getDefault().getActiveShell(), "Error creating node", "Error creating child of "+thisNodeType+" with type "+childNodeType+": "+e); return; } } else if (parentSk!=SerializationKind.FOLDER && childSk==SerializationKind.METADATA_PARTIAL) { createDomChild(childNodeName, childNodeType); } else { if (childNodeType.equals("nt:file")) { IFolder f = (IFolder)resource; createNtFile(f, childNodeName, childNodeType); return; } //TODO: FILE not yet supported Activator.getDefault().getPluginLogger() .error("Cannot create child node of type " + childNodeType + ", serializationKind " + childSk + " under child node of type " + thisNodeType + ", serializationKind " + parentSk); MessageDialog.openWarning(Display.getDefault().getActiveShell(), "Error creating node", "Cannot create child of "+thisNodeType+" with type "+childNodeType+" (yet?)"); return; } } void createDomChild(String childNodeName, String childNodeType) { boolean underlyingMatch = underlying==properties.getUnderlying(); if (domElement==properties.getDomElement()) { // normal case try{ createChild(childNodeName, childNodeType, domElement, underlying); } catch(Exception e) { MessageDialog.openError(Display.getDefault().getActiveShell(), "Error creating new JCR node", "The following error occurred: "+e.getMessage()); } } else { // trickier case try{ createChild(childNodeName, childNodeType, properties.getDomElement(), properties.getUnderlying()); } catch(Exception e) { MessageDialog.openError(Display.getDefault().getActiveShell(), "Error creating new JCR node", "The following error occurred: "+e.getMessage()); } } } private void createVaultFile(IFolder parent, String filename, String childNodeType) { createVaultFileWithContent(parent, filename, childNodeType, null); } private void createVaultFileWithContent(IFolder parent, String filename, String childNodeType, Element content) { String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<jcr:root \n xmlns:sling=\"http://sling.apache.org/jcr/sling/1.0\"\n xmlns:jcr=\"http://www.jcp.org/jcr/1.0\"\n jcr:primaryType=\""+childNodeType+"\"/>"; final IFile file = parent.getFile(filename); try { if (content!=null) { Document document = TolerantXMLParser.parse(xml, file.getFullPath().toOSString()); // add the attributes of content List<Attribute> attributes = content.getAttributes(); for (Attribute attribute : attributes) { if (attribute.getName().equals("jcr:primaryType")) { // skip this continue; } document.getRootElement().addAttribute(attribute); } // then copy all the children document.getRootElement().addNodes(content.getChildren()); // then save the document xml = document.toXML(); } if (file.exists()) { file.setContents(new ByteArrayInputStream(xml.getBytes()), true, true, new NullProgressMonitor()); } else { file.create(new ByteArrayInputStream(xml.getBytes()), true, new NullProgressMonitor()); } } catch (Exception e) { //TODO proper logging e.printStackTrace(); MessageDialog.openInformation(Display.getDefault().getActiveShell(), "Cannot create JCR node on a File", "Following Exception encountered: "+e); } } private void createNtFile(IFolder parent, String filename, String childNodeType) { IFile file = parent.getFile(filename); if (file.exists()) { // file already exists return; } try { file.create(new ByteArrayInputStream("".getBytes()), true, new NullProgressMonitor()); } catch (CoreException e) { //TODO proper logging e.printStackTrace(); MessageDialog.openWarning(Display.getDefault().getActiveShell(), "Cannot create file "+filename, "Following Exception encountered: "+e); } } private SerializationKind getFallbackSerializationKind(String nodeType) { if (nodeType.equals("nt:file")) { return SerializationKind.FILE; } else if (probablyFolderType(nodeType)) { return SerializationKind.FOLDER; } else { return SerializationKind.METADATA_PARTIAL; } } protected void createChild(String nodeName, String nodeType, Element domElement, GenericJcrRootFile effectiveUnderlying) { if (domElement==null) { throw new IllegalArgumentException("domNode must not be null"); } if (effectiveUnderlying==null) { throw new IllegalArgumentException("effectiveUnderlying must not be null"); } Element element = new Element(nodeName); if (nodeType!=null) { element.addAttribute("jcr:primaryType", nodeType); } StringBuilder indent = new StringBuilder(); Element parElement = domElement.getParentElement(); while(parElement!=null) { indent.append(" "); parElement = parElement.getParentElement(); } domElement.addNode(new Text("\n "+indent.toString())); element = domElement.addNode(element); domElement.addNode(new Text("\n"+indent.toString())); JcrNode childNode = new JcrNode(this, element, null); effectiveUnderlying.save(); } public boolean canBeDeleted() { if (parent==null) { return false; } if (resource!=null) { // can be a file or a folder (project is virtually impossible) return true; } if (domElement!=null && underlying!=null) { return true; } return false; } public void delete() { if (parent==null) { // then I dont know how to delete return; } parent.children.remove(this); if (resource!=null) { IWorkspaceRunnable r = new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { resource.delete(true, monitor); if (dirSibling!=null) { dirSibling.getResource().delete(true, monitor); } } }; try { ResourcesPlugin.getWorkspace().run(r, null); } catch (CoreException e) { Activator.getDefault().getPluginLogger().error("Error renaming resource ("+resource+"): "+e, e); } } if (domElement!=null) { Element parentNode = domElement.getParentElement(); domElement.remove(); if (parentNode!=null) { List<Node> allChildNodes = parentNode.getNodes(); boolean nonTextChild = false; for (Iterator<Node> it = allChildNodes.iterator(); it .hasNext();) { Node node = it.next(); if (node.getType()!=Type.TEXT) { nonTextChild = true; } } if (!nonTextChild) { for (Iterator<Node> it = allChildNodes.iterator(); it .hasNext();) { Node node = it.next(); it.remove(); } if (!parentNode.hasNodes()) { parentNode.setCompactEmpty(true); } } } } if (underlying!=null) { underlying.save(); } } public IProject getProject() { if (resource!=null) { return resource.getProject(); } if (underlying!=null) { return underlying.file.getProject(); } return null; } public boolean isInContentXml() { return domElement!=null; } public boolean canCreateChild() { try { final IProject project = getProject(); final Filter filter = ProjectUtil.loadFilter(project); final String relativeFilePath = getJcrPath(); // final Repository repository = Activator.getDefault().getRepositoryFactory().newRepository(null);//ServerUtil.getRepository(null, null); // final RepositoryInfo repositoryInfo = repository.getRepositoryInfo(); // if (repositoryInfo==null) { // return false; // } if (filter==null) { Activator.getDefault().getPluginLogger().error("No filter.xml found for "+project); return true; } else { final FilterResult result = filter.filter(relativeFilePath); return result==FilterResult.ALLOW; } } catch (CoreException e) { Logger logger = Activator.getDefault().getPluginLogger(); logger.error("Could not verify child node allowance: "+this, e); return false; } } public String getPrimaryType() { final String pt = properties.getValue("jcr:primaryType"); if (pt!=null && pt.length()!=0) { return pt; } if (resource!=null) { if (resource instanceof IContainer) { return "nt:folder"; } else { return "nt:file"; } } return ""; } public void deleteProperty(String displayName) { properties.deleteProperty(displayName); } public SyncDir getSyncDir() { return getParent().getSyncDir(); } public void setPropertyValue(Object key, Object value) { properties.setPropertyValue(key, value); } void changePrimaryType(String newPrimaryType) { Repository repository = ServerUtil.getDefaultRepository(getProject()); NodeTypeRegistry ntManager = (repository==null) ? null : repository.getNodeTypeRegistry(); if (ntManager == null) { MessageDialog.openWarning(null, "Unable to change primary type", "Unable to change primary type since project " + getProject().getName() + " is not associated with a server or the server is not started."); return; } try { if (!ntManager.isAllowedPrimaryChildNodeType(getParent().getPrimaryType(), newPrimaryType)) { if (!MessageDialog.openQuestion(null, "Unable to change primary type", "Parent (type '"+getParent().getPrimaryType()+"')"+ " does not accept child with primary type '"+newPrimaryType+"'. Change anyway?")) { return; } } } catch (RepositoryException e1) { MessageDialog.openWarning(null, "Unable to change primary type", "Exception occured while trying to "+ "verify node types: "+e1); return; } String thisNodeType = getPrimaryType(); final SerializationKind currentSk = getSerializationKind(thisNodeType); final SerializationKind newSk = getSerializationKind(newPrimaryType); if (currentSk.equals(newSk)) { if (newSk!=SerializationKind.FOLDER) { // easiest - we should just be able to change the type in the .content.xml properties.doSetPropertyValue("jcr:primaryType", newPrimaryType); } else { if (thisNodeType.equals("nt:folder")) { // switching away from an nt:folder might require creating a .content.xml createVaultFile((IFolder) resource, ".content.xml", newPrimaryType); } else if (newPrimaryType.equals("nt:folder")) { // switching *to* an nt:folder also has its challenges..: // 1) it is not allowed to occur within a 'default' and 'full coverage aggregate' node // 2) nt:folder doesn't allow arbitrary children for one // 3) but it also doesn't have an extra .content.xml - so that one would disappear // 1) if (domElement!=null) { MessageDialog.openWarning(null, "Unable to change primaryType", "Unable to change jcr:primaryType to nt:folder" + " since the node is contained in a .content.xml"); return; } // verify 2) if (!verifyNodeTypeChange(ntManager, newPrimaryType)) { return; } if (!(resource instanceof IFolder)) { MessageDialog.openWarning(null, "Unable to change primaryType", "Unable to change jcr:primaryType to nt:folder" + " as there is no underlying folder"); return; } IFolder folder = (IFolder)resource; // 3) delete the .content.xml IFile contentXml = folder.getFile(".content.xml"); if (contentXml.exists()) { try { contentXml.delete(true, new NullProgressMonitor()); } catch (CoreException e) { Logger logger = Activator.getDefault().getPluginLogger(); logger.error("Could not delete "+contentXml.getFullPath()+", e="+e, e); MessageDialog.openError(null, "Could not delete file", "Could not delete "+contentXml.getFullPath()+", "+e); } } } else { properties.doSetPropertyValue("jcr:primaryType", newPrimaryType); } } return; } if (newSk==SerializationKind.FOLDER) { // switching to a folder if (currentSk==SerializationKind.FILE) { MessageDialog.openWarning(null, "Unable to change primary type", "Changing from a file to a folder type is currently not supported"); return; } if (newPrimaryType.equals("nt:folder")) { // verify if (!verifyNodeTypeChange(ntManager, newPrimaryType)) { return; } } try { // create the new directory structure pointing to 'this' IFolder newFolder = getParent().prepareCreateFolderChild(getJcrPathName()); if (!newPrimaryType.equals("nt:folder")) { // move any children from the existing 'this' to a new vault file createVaultFileWithContent(newFolder, ".content.xml", newPrimaryType, domElement); } // remove myself if (domElement!=null) { domElement.remove(); if (underlying!=null) { underlying.save(); } } // add a pointer in the corresponding .content.xml to point to this (folder) child getParent().createDomChild(getJcrPathName(), null); if (newPrimaryType.equals("nt:folder")) { // delete the .content.xml if (properties!=null && properties.getUnderlying()!=null) { IFile contentXml = properties.getUnderlying().file; if (contentXml!=null && contentXml.exists()) { contentXml.delete(true, new NullProgressMonitor()); } } } ServerUtil.triggerIncrementalBuild(newFolder, null); return; } catch (CoreException e) { MessageDialog.openWarning(null, "Unable to change primaryType", "Exception occurred: "+e); Logger logger = Activator.getDefault().getPluginLogger(); logger.error("Exception occurred", e); return; } } else if (newSk==SerializationKind.FILE) { MessageDialog.openWarning(null, "Unable to change primary type", "Changing to/from a file is currently not supported"); return; } else { // otherwise we're going from a folder to partial-or-full if (domElement==null && (resource instanceof IFolder)) { createVaultFile((IFolder) resource, ".content.xml", newPrimaryType); } else { // set the "pointer"'s jcr:primaryType if (domElement.getAttributeMap().containsKey("jcr:primaryType")) { domElement.setAttribute("jcr:primaryType", newPrimaryType); } else { domElement.addAttribute("jcr:primaryType", newPrimaryType); } // then copy all the other attributes - plus children if there are nay Element propDomElement = properties.getDomElement(); if (propDomElement!=null) { List<Attribute> attributes = propDomElement.getAttributes(); for (Iterator<Attribute> it = attributes.iterator(); it.hasNext();) { Attribute anAttribute = it.next(); if (anAttribute.getName().startsWith("xmlns:")) { continue; } if (anAttribute.getName().equals("jcr:primaryType")) { continue; } if (domElement.getAttributeMap().containsKey(anAttribute.getName())) { domElement.setAttribute(anAttribute.getName(), anAttribute.getValue()); } else { domElement.addAttribute(anAttribute); } } List<Element> c2 = propDomElement.getChildren(); if (c2!=null && c2.size()!=0) { domElement.addNodes(c2); } } if (properties.getUnderlying()!=null && properties.getUnderlying().file!=null) { try { properties.getUnderlying().file.delete(true, new NullProgressMonitor()); // prune empty directories: prune(properties.getUnderlying().file.getParent()); } catch (CoreException e) { MessageDialog.openError(null, "Unable to change primary type", "Could not delete vault file "+properties.getUnderlying().file+": "+e); Activator.getDefault().getPluginLogger().error("Error changing jcr:primaryType. Could not delete vault file "+properties.getUnderlying().file+": "+e.getMessage(), e); return; } } underlying.save(); } } } private void prune(IContainer folder) throws CoreException { if (folder==null || !(folder instanceof IFolder)) { return; } IFolder f = (IFolder)folder; IResource[] members = f.members(); if (members!=null && members.length!=0) { return; } f.delete(true, new NullProgressMonitor()); prune(folder.getParent()); } private boolean verifyNodeTypeChange(NodeTypeRegistry ntManager, final String newNodeType) { Object[] cn = getChildren(true); for (int i = 0; i < cn.length; i++) { JcrNode node = (JcrNode) cn[i]; try { if (!ntManager.isAllowedPrimaryChildNodeType(newNodeType, node.getPrimaryType())) { MessageDialog.openWarning(null, "Unable to change primaryType", "Unable to change jcr:primaryType to nt:folder" + " since nt:folder cannot have child of type "+node.getPrimaryType()); return false; } } catch (RepositoryException e) { Logger logger = Activator.getDefault().getPluginLogger(); logger.error("Could not determine allowed primary child node types", e); } } return true; } public void addProperty(String name, String value) { properties.addProperty(name, value); } public NodeType getNodeType() { Repository repository = ServerUtil.getDefaultRepository(getProject()); NodeTypeRegistry ntManager = (repository==null) ? null : repository.getNodeTypeRegistry(); if (ntManager==null) { return null; } return ntManager.getNodeType(getPrimaryType()); } public int getPropertyType(String propertyName) { PropertyDefinition pd = getPropertyDefinition(propertyName); if (pd!=null) { return pd.getRequiredType(); } // otherwise use the SerializationManager to read the // underlying vault file and derive the propertyType from there GenericJcrRootFile u = properties.getUnderlying(); if (u==null) { // no underlying properties file, that's not good Activator.getDefault().getPluginLogger().warn("No underlying properties file, cannot derive propertyType ("+propertyName+") for "+this); return -1; } IFolder contentSyncRoot = ProjectUtil.getSyncDirectory(getProject()); IFile file = (IFile) u.file; try (InputStream contents = file.getContents() ){ String resourceLocation = file.getFullPath().makeRelativeTo(contentSyncRoot.getFullPath()) .toPortableString(); ResourceProxy resourceProxy = Activator.getDefault() .getSerializationManager().readSerializationData(resourceLocation, contents); // resourceProxy could be containing a full tree // dive into the right position String rawValue = properties.getValue(propertyName); return PropertyTypeSupport.propertyTypeOfString(rawValue); } catch(Exception e) { Activator.getDefault().getPluginLogger().warn("Exception occurred during analyzing propertyType ("+propertyName+") for "+this, e); } return -1; } private Object doGetProperty(ResourceProxy resourceProxy, String propertyName) { if (resourceProxy.getPath().equals(getJcrPath())) { Map<String, Object> props = resourceProxy.getProperties(); if (props.containsKey(propertyName)) { Object p0 = props.get(propertyName); return p0; } } else { List<ResourceProxy> resourceProxyChildren = resourceProxy.getChildren(); for (Iterator<ResourceProxy> it = resourceProxyChildren.iterator(); it .hasNext();) { final ResourceProxy aChild = it.next(); final Object p1 = doGetProperty(aChild, propertyName); if (p1!=null) { return p1; } } } return null; } public PropertyDefinition getPropertyDefinition(String propertyName) { NodeType nt0 = getNodeType(); if (nt0==null) { return null; } List<NodeType> nodeTypes = new LinkedList<>(); nodeTypes.add(nt0); // add all supertypes nodeTypes.addAll(Arrays.asList(nt0.getSupertypes())); for (Iterator<NodeType> it = nodeTypes.iterator(); it.hasNext();) { NodeType nt = it.next(); PropertyDefinition[] pds = nt.getPropertyDefinitions(); for (int i = 0; i < pds.length; i++) { PropertyDefinition propertyDefinition = pds[i]; if (propertyDefinition.getName().equals(propertyName)) { return propertyDefinition; } } } return null; } public JcrProperty getProperty(final String name) { if (properties==null) { return null; } return new JcrProperty() { @Override public String getName() { return name; } @Override public int getType() { return getPropertyType(name); } @Override public String getTypeAsString() { int t = getPropertyType(name); return PropertyType.nameFromValue(t); }; // @Override // public Object getValue() { // throw new IllegalStateException("not yet implemented"); // } @Override public String getValueAsString() { String rawValue = getProperties().getValue(name); if (rawValue==null) { return null; } if (rawValue.startsWith("{")) { int curlyEnd = rawValue.indexOf("}", 1); rawValue = rawValue.substring(curlyEnd+1); } return rawValue; } @Override public boolean isMultiple() { String rawValue = getProperties().getValue(name); if (rawValue==null) { return false; } if (rawValue.startsWith("{")) { int curlyEnd = rawValue.indexOf("}", 1); rawValue = rawValue.substring(curlyEnd+1); } return rawValue.startsWith("[") && rawValue.endsWith("]"); } @Override public String[] getValuesAsString() { String rawValue = getProperties().getValue(name); if (rawValue.startsWith("{")) { int curlyEnd = rawValue.indexOf("}", 1); rawValue = rawValue.substring(curlyEnd+1); } rawValue = rawValue.substring(1, rawValue.length()-1); return org.apache.jackrabbit.util.Text.explode(rawValue, ','); } }; } public void renameProperty(String oldKey, String newKey) { properties.renameProperty(oldKey, newKey); } public void changePropertyType(String key, int propertyType) { properties.changePropertyType(key, propertyType); } private IFolder prepareCreateFolderChild(final String childNodeName) throws CoreException { // 0) find base folder for creating new subfolders List<String> parentNames = new LinkedList<>(); JcrNode node = JcrNode.this; while(!(node.resource instanceof IFolder) && !(node instanceof SyncDir)) { parentNames.add(0, node.getJcrPathName()); node = node.getParent(); } if (!(node.resource instanceof IFolder)) { throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Could not find base folder for creating child. (1) Expected a folder at "+node.resource)); } IFolder folder = (IFolder) node.resource; parentNames.add(childNodeName); for (Iterator<String> it = parentNames.iterator(); it .hasNext();) { String aParentName = it.next(); String encodedParentName = DirNode.encode(aParentName); IResource member = folder.findMember(encodedParentName); if (member!=null && !(member instanceof IFolder)) { throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Could not find base folder for creating child. (2) Expected a folder at "+member)); } if (member!=null && member.exists()) { folder = (IFolder) member; it.remove(); continue; } folder = folder.getFolder(encodedParentName); if (!folder.exists()) { folder.create(true, true, new NullProgressMonitor()); } } return folder; } public IStatus validateDrop(int operation, TransferData transferType) { Repository repository = ServerUtil.getDefaultRepository(getProject()); NodeTypeRegistry ntManager = (repository==null) ? null : repository.getNodeTypeRegistry(); if (ntManager == null) { return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, 1, "Cannot drop element here because corresponding server is not started! (Needed to determine node types)", null); } // let's support plain files first try { if (getPrimaryType().equals("nt:file")) { // hard-code the most prominent case: cannot drop onto a file return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, 1, "Cannot drop element onto nt:file", null); } if (ntManager.isAllowedPrimaryChildNodeType(getPrimaryType(), "nt:file")) { return Status.OK_STATUS; } else { return Status.CANCEL_STATUS; } } catch (RepositoryException e) { Activator.getDefault().getPluginLogger().error("validateDrop: Got Exception while " + "verifying nodeType: "+e, e); return Status.CANCEL_STATUS; } } public IStatus handleDrop(Object data, int detail) throws CoreException { IFolder folder = (IFolder)this.resource; if (data instanceof IStructuredSelection) { IStructuredSelection sel = (IStructuredSelection)data; Object firstElem = sel.getFirstElement(); if (firstElem instanceof IResource) { IResource resource = (IResource)firstElem; return handleDropResource(folder, resource, detail); } else if (firstElem instanceof JcrNode) { JcrNode node = (JcrNode)firstElem; return handleDropNode(folder, node, detail); } else { return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, 1, "Cannot drop on this type of element (yet) [1]", null); } } else { return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, 1, "Cannot drop this type of selection", null); } } private IStatus handleDropNode(IFolder targetFolder, JcrNode droppedNode, int dropDetail) throws CoreException { if (domElement!=null && droppedNode.domElement!=null && droppedNode.resource==null) { // then this is the case of moving/copying a dom tree domElement.addNodes(droppedNode.domElement.copy()); underlying.save(); if (dropDetail==DND.DROP_MOVE) { // then delete the original droppedNode.delete(); } return Status.OK_STATUS; } if (droppedNode.resource!=null && droppedNode.domElement==null) { // this is a pure file/folder based d'n'd IStatus status = handleDropResource(targetFolder, droppedNode.resource, dropDetail); if (!status.isOK()) { return status; } if (droppedNode.dirSibling!=null) { return handleDropResource(targetFolder, droppedNode.dirSibling.getResource(), dropDetail); } return Status.OK_STATUS; } //TODO mixed cases are more advanced and not yet supported return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, 1, "Cannot drop on this (mixed) type of element (yet) [2]", null); } private IStatus handleDropResource(IFolder targetFolder, IResource droppedResourceRoot, int detail) throws CoreException { if (targetFolder==null) { return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, 1, "Cannot drop on this type of element (yet)", null); } if (droppedResourceRoot==null) { throw new IllegalArgumentException("droppedResourceRoot must not be null"); } IFile copyToFile = targetFolder.getFile(droppedResourceRoot.getName()); IPath copyToPath = copyToFile.getFullPath(); switch (detail) { case DND.DROP_COPY: { droppedResourceRoot.copy(copyToPath, true, new NullProgressMonitor()); break; } case DND.DROP_MOVE: { droppedResourceRoot.move(copyToPath, true, new NullProgressMonitor()); break; } default: { throw new IllegalStateException("Unknown drop action (detail: " + detail + ")"); } } return Status.OK_STATUS; } public IContainer getDropContainer() { if (resource instanceof IContainer) { return (IContainer) resource; } else { return null; } } public boolean canBeCopiedToClipboard() { if (getPrimaryType().equals("nt:file")) { return true; } else if (domElement!=null && resource==null) { // plain dom node/sub-tree - which we support via XML return true; } else { // everything else: not yet supported return false; } } public void copyToClipboard(Clipboard clipboard) { if (!canBeCopiedToClipboard()) { MessageDialog.openWarning(null, "Cannot copy", "Cannot copy this type of node (yet)"); return; } if (getPrimaryType().equals("nt:file")) { copyFileToClipboard(clipboard); } else if (domElement!=null && resource==null) { copyDomToClipboard(clipboard); } } private void copyDomToClipboard(Clipboard clipboard) { String text = domElement.toXML(); clipboard.setContents(new Object[] {text}, new Transfer[] {TextTransfer.getInstance()}); } private void copyFileToClipboard(Clipboard clipboard) { final IResource[] resources; final String[] fileNames; if (dirSibling==null) { resources = new IResource[] {resource}; final IPath location = resource.getLocation(); fileNames = (location==null) ? null : new String[] {location.toOSString()}; } else { resources = new IResource[] {resource, dirSibling.getResource()}; final IPath resLocation = resource.getLocation(); final IPath siblLocation = dirSibling.getResource().getLocation(); fileNames = (resLocation==null || siblLocation==null) ? null : new String[] {resLocation.toOSString(), siblLocation.toOSString()}; } if (fileNames!=null) { clipboard.setContents(new Object[] { resources, fileNames }, new Transfer[] { ResourceTransfer.getInstance(), FileTransfer.getInstance()}); } else { clipboard.setContents(new Object[] { resources }, new Transfer[] { ResourceTransfer.getInstance() }); } } public boolean canBePastedTo(Clipboard clipboard) { Repository repository = ServerUtil.getDefaultRepository(getProject()); NodeTypeRegistry ntManager = (repository==null) ? null : repository.getNodeTypeRegistry(); IResource[] resourceData = (IResource[]) clipboard .getContents(ResourceTransfer.getInstance()); if (resourceData!=null) { IContainer container = getDropContainer(); return container!=null; } String[] fileData = (String[]) clipboard.getContents(FileTransfer.getInstance()); if (fileData!=null) { IContainer container = getDropContainer(); return container!=null; } String text = (String) clipboard.getContents(TextTransfer.getInstance()); if (text!=null) { return (domElement!=null); } return false; } /** * Paste from the clipboard to this (container) node. * <p> * Copyright Note: The code of this method was ported from eclipse' * PasteAction, which due to visibility restrictions was not reusable. * <p> * @param clipboard */ public void pasteFromClipboard(Clipboard clipboard) { if (!canBePastedTo(clipboard)) { // should not occur due to 'canBePastedTo' check done by // corresponding action - checking here nevertheless MessageDialog.openInformation(null, "Cannot paste", "No applicable node (type) for pasting found."); return; } Repository repository = ServerUtil.getDefaultRepository(getProject()); NodeTypeRegistry ntManager = (repository==null) ? null : repository.getNodeTypeRegistry(); if (ntManager == null) { MessageDialog.openWarning(null, "Cannot paste", "Cannot paste if corresponding server is not started"); return; } // try the resource transfer IResource[] resourceData = (IResource[]) clipboard.getContents(ResourceTransfer.getInstance()); if (resourceData != null && resourceData.length > 0) { if (resourceData[0].getType() == IResource.PROJECT) { // do not support project pasting onto a jcr node MessageDialog.openInformation(null, "Cannot paste project(s)", "Pasting of a project onto a (JCR) node is not possible"); return; } else { CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(null); operation.copyResources(resourceData, getDropContainer()); } return; } // try the file transfer String[] fileData = (String[]) clipboard.getContents(FileTransfer.getInstance()); if (fileData != null) { CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(null); operation.copyFiles(fileData, getDropContainer()); return; } // then try the text transfer String text = (String) clipboard.getContents(TextTransfer.getInstance()); if ((text!=null) && (this.domElement!=null)) { try { Document document = TolerantXMLParser.parse(text, "pasted from clipboard"); this.domElement.addNode(document.getRootElement()); this.underlying.save(); } catch (IOException e) { MessageDialog.openError(null, "Could not paste from clipboard", "Exception encountered while pasting from clipboard: "+e); Activator.getDefault().getPluginLogger().error("Error pasting from clipboard: "+e, e); } } } }