| /* |
| * 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); |
| } |
| } |
| } |
| |
| } |