### Eclipse Workspace Patch 1.0 #P magnolia-core Index: src/test/java/info/magnolia/link/BaseLinkTest.java =================================================================== --- src/test/java/info/magnolia/link/BaseLinkTest.java (revision 51040) +++ src/test/java/info/magnolia/link/BaseLinkTest.java (working copy) @@ -39,8 +39,12 @@ import info.magnolia.cms.beans.config.URI2RepositoryManager; import info.magnolia.cms.beans.runtime.FileProperties; import info.magnolia.cms.core.BinaryNodeData; +import info.magnolia.cms.core.Content; +import info.magnolia.cms.core.DefaultContent; import info.magnolia.cms.i18n.DefaultI18nContentSupport; import info.magnolia.cms.i18n.I18nContentSupport; +import info.magnolia.cms.util.ContentUtil; +import info.magnolia.cms.util.NodeDataUtil; import info.magnolia.context.MgnlContext; import info.magnolia.context.WebContext; import info.magnolia.repository.RepositoryConstants; @@ -49,11 +53,16 @@ import info.magnolia.test.mock.MockContent; import info.magnolia.test.mock.MockHierarchyManager; import info.magnolia.test.mock.MockUtil; +import info.magnolia.test.mock.jcr.MockNode; +import info.magnolia.test.mock.jcr.MockSession; +import info.magnolia.test.mock.jcr.SessionTestUtil; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; +import javax.jcr.Session; + import org.junit.Before; /** @@ -75,9 +84,9 @@ protected List allMocks; protected String website = - "/parent@uuid=1\n" + - "/parent/sub@uuid=2\n" + - "/parent/sub2@uuid=3"; + "/parent.@uuid=1\n" + + "/parent/sub.@uuid=2\n" + + "/parent/sub2.@uuid=3"; @Override @@ -85,14 +94,15 @@ public void setUp() throws Exception { super.setUp(); - MockHierarchyManager hm = MockUtil.createHierarchyManager(RepositoryConstants.WEBSITE, website); + Session session = SessionTestUtil.createSession(RepositoryConstants.WEBSITE, website); webContext = createMock(WebContext.class); - expect(webContext.getHierarchyManager(RepositoryConstants.WEBSITE)).andReturn(hm).anyTimes(); expect(webContext.getContextPath()).andReturn(SOME_CONTEXT).anyTimes(); + expect(webContext.getJCRSession(RepositoryConstants.WEBSITE)).andReturn(session).anyTimes(); // add a binary - MockContent page = (MockContent) hm.getContent(HANDLE_PARENT_SUB); - BinaryNodeData bmnd = page.addBinaryNodeData("file"); + MockNode page = (MockNode) session.getNode(HANDLE_PARENT_SUB); + DefaultContent content = (DefaultContent) ContentUtil.asContent(page); + BinaryNodeData bmnd = content.addBinaryNodeData("file"); bmnd.setAttribute(FileProperties.PROPERTY_FILENAME, "test"); bmnd.setAttribute(FileProperties.PROPERTY_EXTENSION, "jpg"); bmnd.setAttribute("jcr:mimeType", "image/jpeg"); Index: src/main/java/info/magnolia/link/LinkFactory.java =================================================================== --- src/main/java/info/magnolia/link/LinkFactory.java (revision 51040) +++ src/main/java/info/magnolia/link/LinkFactory.java (working copy) @@ -33,22 +33,27 @@ */ package info.magnolia.link; +import info.magnolia.cms.beans.config.URI2RepositoryManager; +import info.magnolia.cms.core.Content; +import info.magnolia.cms.core.NodeData; +import info.magnolia.cms.i18n.I18nContentSupportFactory; +import info.magnolia.context.MgnlContext; +import info.magnolia.exception.RuntimeRepositoryException; +import info.magnolia.repository.RepositoryConstants; + import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.jcr.AccessDeniedException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; import javax.jcr.RepositoryException; -import javax.jcr.PathNotFoundException; +import javax.jcr.Session; import org.apache.commons.lang.StringUtils; -import info.magnolia.cms.beans.config.URI2RepositoryManager; -import info.magnolia.cms.core.Content; -import info.magnolia.cms.core.HierarchyManager; -import info.magnolia.cms.core.NodeData; -import info.magnolia.cms.i18n.I18nContentSupportFactory; -import info.magnolia.context.MgnlContext; -import info.magnolia.repository.RepositoryConstants; - /** * Factory processing various input into the Link objects and back. * For parsing html and converting multiple link instances on the fly use {@link LinkUtil}. @@ -63,19 +68,21 @@ * Creates new link from the content node. * @param node Target content for the link. * @return Link pointing to the provided content. + * @deprecated since 4.5, use {@link #createLink(Node)} instead. */ public static Link createLink(Content node) { - return new Link(node); + return createLink(node.getJCRNode()); } /** * Creates new link from the node data. * @param nodeData Target node data for the link. * @return Link pointing to the provided node data. + * @deprecated since 4.5, use {@link #createLink(Property)} instead. */ public static Link createLink(NodeData nodeData) throws LinkException { try { - return new Link(nodeData.getParent().getWorkspace().getName(), nodeData.getParent(), nodeData); + return createLink(nodeData.getJCRProperty()); } catch (RepositoryException e) { throw new LinkException("can't find node " + nodeData , e); } @@ -83,15 +90,15 @@ /** * Creates link to the content denoted by repository and uuid. - * @param repository Parent repository of the content of interest. - * @param uuid UUID of the content to create link to. - * @return link to the content with provided UUID. + * @param workspace Parent workspace of the content of interest. + * @param id identifier of the content to create link to. + * @return link to the content with provided identifier. */ - public static Link createLink(String repository, String uuid) throws LinkException { + public static Link createLink(String workspace, String id) throws LinkException { try { - return new Link(MgnlContext.getHierarchyManager(repository).getContentByUUID(uuid)); + return new Link(MgnlContext.getJCRSession(workspace).getNodeByIdentifier(id)); } catch (RepositoryException e) { - throw new LinkException("can't get node with uuid " + uuid + " and repository " + repository); + throw new LinkException("can't get node with identifier " + id + " and workspace " + workspace); } } @@ -106,12 +113,12 @@ * @throws LinkException */ public static Link createLink(String repository, String path, String extension, String anchor, String parameters) throws LinkException { - Content node = null; + Node node = null; String fileName = null; - String nodeDataName = null; - NodeData nodeData = null; + String propertyName = null; + Property property = null; try { - HierarchyManager hm = MgnlContext.getHierarchyManager(repository); + Session session = MgnlContext.getJCRSession(repository); boolean exists = false; try { // jackrabbit own path parser @@ -126,24 +133,24 @@ // ignore - parser doesn't exists } } - exists = hm.isExist(path) && !hm.isNodeData(path); + exists = session.nodeExists(path) && !session.propertyExists(path); if (exists) { - node = hm.getContent(path); + node = session.getNode(path); } if (node == null) { // this is a binary containing the name at the end // this name is stored as an attribute but is not part of the handle - if (hm.isNodeData(StringUtils.substringBeforeLast(path, "/"))) { + if (session.propertyExists(StringUtils.substringBeforeLast(path, "/"))) { fileName = StringUtils.substringAfterLast(path, "/"); path = StringUtils.substringBeforeLast(path, "/"); } // link to the binary node data - if (hm.isNodeData(path)) { - nodeDataName = StringUtils.substringAfterLast(path, "/"); + if (session.propertyExists(path)) { + propertyName = StringUtils.substringAfterLast(path, "/"); path = StringUtils.substringBeforeLast(path, "/"); - node = hm.getContent(path); - nodeData = node.getNodeData(nodeDataName); + node = session.getNode(path); + property = node.getProperty(propertyName); } } if (node == null) { @@ -158,46 +165,46 @@ link.setExtension(extension); link.setParameters(parameters); link.setFileName(fileName); - link.setNodeDataName(nodeDataName); - link.setNodeData(nodeData); - link.setHandle(path); + link.setPropertyName(propertyName); + link.setProperty(property); + link.setPath(path); return link; } /** * Creates link based on provided parameters. Should the uuid be non existent or the fallback handle invalid, creates nonetheless an "undefined" {@link Link} object, * pointing to the non existing uuid so that broken link detection tools can find it. - * @param uuid UUID of the content - * @param repository Content repository name. - * @param fallbackHandle Optional fallback content handle. - * @param nodeDataName Content node data name for binary data. + * @param identifier of the content + * @param workspace Content workspace name. + * @param fallbackPath Optional fallback content path. + * @param propertyName Node property name for binary data. * @param extension Optional link extension. * @param anchor Optional link anchor. * @param parameters Optional link parameters. - * @return Link pointing to the content denoted by uuid and repository. Link is created using all provided optional values if present. + * @return Link pointing to the content denoted by identifier and workspace. Link is created using all provided optional values if present. * @throws LinkException */ - public static Link createLink(String uuid, String repository, String fallbackHandle, String nodeDataName, String extension, String anchor, String parameters) throws LinkException { - final String defaultRepository = StringUtils.defaultIfEmpty(repository, RepositoryConstants.WEBSITE); + public static Link createLink(String identifier, String workspace, String fallbackPath, String propertyName, String extension, String anchor, String parameters) throws LinkException { + final String defaultWorkspace = StringUtils.defaultIfEmpty(workspace, RepositoryConstants.WEBSITE); Link link; try { - link = createLink(defaultRepository, uuid); + link = createLink(defaultWorkspace, identifier); } catch (LinkException e) { try { - final Content node = MgnlContext.getHierarchyManager(defaultRepository).getContent(fallbackHandle != null? fallbackHandle:""); + final Node node = MgnlContext.getJCRSession(defaultWorkspace).getNode(fallbackPath != null? fallbackPath:""); link = createLink(node); } catch (PathNotFoundException pnfe) { - log.warn("Can't find node with uuid {} or handle {} in repository {}", new Object[]{ uuid, fallbackHandle, defaultRepository}); + log.warn("Can't find node with identifier {} or path {} in workspace {}", new Object[]{ identifier, fallbackPath, defaultWorkspace}); link = new Link(); - link.setUUID(uuid); + link.setIdentifier(identifier); } catch (RepositoryException re) { - log.warn("Can't find node with uuid {} or handle {} in repository {}", new Object[]{ uuid, fallbackHandle, defaultRepository}); + log.warn("Can't find node with identifier {} or path {} in workspace {}", new Object[]{ identifier, fallbackPath, defaultWorkspace}); link = new Link(); - link.setUUID(uuid); + link.setIdentifier(identifier); } } - link.setFallbackHandle(fallbackHandle); - link.setNodeDataName(nodeDataName); + link.setFallbackPath(fallbackPath); + link.setPropertyName(propertyName); link.setExtension(extension); link.setAnchor(anchor); link.setParameters(parameters); @@ -245,9 +252,9 @@ */ public static String toPattern(Link link) { return "${link:{" - + "uuid:{" + link.getUUID() + "}," - + "repository:{" + link.getRepository() + "}," - + "handle:{" + link.getHandle() + "}," // original handle represented by the uuid + + "uuid:{" + link.getIdentifier() + "}," + + "repository:{" + link.getWorkspace() + "}," + + "handle:{" + link.getPath() + "}," // original handle represented by the uuid + "nodeData:{" + StringUtils.defaultString(link.getNodeDataName()) + "}," // in case of binaries + "extension:{" + StringUtils.defaultString(link.getExtension()) + "}" // the extension to use if no extension can be resolved otherwise + "}}" @@ -279,4 +286,21 @@ "(#([^\\?\"]*))?" + // anchor "(\\?([^\"]*))?" // parameters ); + + public static Link createLink(Property property) { + try { + Node parent = property.getParent(); + return new Link(parent.getSession().getWorkspace().getName(), parent, property); + } catch (AccessDeniedException e) { + throw new RuntimeRepositoryException(e); + } catch (ItemNotFoundException e) { + throw new RuntimeRepositoryException(e); + } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } + } + + public static Link createLink(Node node) { + return new Link(node); + } } Index: src/main/java/info/magnolia/link/EditorLinkTransformer.java =================================================================== --- src/main/java/info/magnolia/link/EditorLinkTransformer.java (revision 51040) +++ src/main/java/info/magnolia/link/EditorLinkTransformer.java (working copy) @@ -50,13 +50,13 @@ protected LinkTransformer linkTransformer = new AbsolutePathTransformer(true,true,false); @Override - public String transform(Link uuidLink) { + public String transform(Link identifierLink) { // TODO use a better way to determine if this is a binary // this should actually not even be here because totally related to the fck editor - if(uuidLink.getNodeData()!=null){ - return binaryTransformer.transform(uuidLink); + if(identifierLink.getNodeData() != null){ + return binaryTransformer.transform(identifierLink); } - return linkTransformer.transform(uuidLink); + return linkTransformer.transform(identifierLink); } } Index: src/test/java/info/magnolia/link/LinkUtilTest.java =================================================================== --- src/test/java/info/magnolia/link/LinkUtilTest.java (revision 51040) +++ src/test/java/info/magnolia/link/LinkUtilTest.java (working copy) @@ -74,13 +74,13 @@ @Test public void testParsingLinks() { - String res = LinkUtil.convertAbsoluteLinksToUUIDs(HTML_WITH_ABSOLUTE_LINK); + String res = LinkUtil.convertAbsoluteLinksToIdentifiers(HTML_WITH_ABSOLUTE_LINK); assertEquals(HTML_WITH_UUIDS, res); } @Test public void testParsingLinksWithBackslashInQueryParam() { - String res = LinkUtil.convertAbsoluteLinksToUUIDs("look here for results"); + String res = LinkUtil.convertAbsoluteLinksToIdentifiers("look here for results"); assertEquals("look here for results", res); } @@ -121,31 +121,31 @@ private void doTestParsingLinks(String expectedHref, String originalHref) { final String originalHtml = "this is a test, yo."; final String expectedHtml = "this is a test, yo."; - final String res = LinkUtil.convertAbsoluteLinksToUUIDs(originalHtml); + final String res = LinkUtil.convertAbsoluteLinksToIdentifiers(originalHtml); assertEquals(expectedHtml, res); } @Test public void testUUIDToAbsoluteLinks() throws LinkException { - String res = LinkUtil.convertLinksFromUUIDPattern(HTML_WITH_UUIDS, LinkTransformerManager.getInstance().getAbsolute(false)); + String res = LinkUtil.convertLinksFromIdentifierPattern(HTML_WITH_UUIDS, LinkTransformerManager.getInstance().getAbsolute(false)); assertEquals(HTML_WITH_ABSOLUTE_LINK, res); } @Test public void testUUIDToInternalLinks() throws LinkException { - String res = LinkUtil.convertLinksFromUUIDPattern(HTML_WITH_UUIDS, LinkTransformerManager.getInstance().getEditorLink()); + String res = LinkUtil.convertLinksFromIdentifierPattern(HTML_WITH_UUIDS, LinkTransformerManager.getInstance().getEditorLink()); assertEquals(HTML_WITH_ABSOLUTE_LINK_AND_CONTEXT_PATH, res); } @Test public void testUUIDToRootLinks() throws LinkException { - String res = LinkUtil.convertLinksFromUUIDPattern("

Large article pages have a Table Of Contents (TOC) navigation.

", LinkTransformerManager.getInstance().getEditorLink()); + String res = LinkUtil.convertLinksFromIdentifierPattern("

Large article pages have a Table Of Contents (TOC) navigation.

", LinkTransformerManager.getInstance().getEditorLink()); assertEquals("

Large article pages have a Table Of Contents (TOC) navigation.

", res); } @Test public void testUUIDToRelativeLinks() throws LinkException { - String res = LinkUtil.convertLinksFromUUIDPattern(HTML_WITH_UUIDS, LinkTransformerManager.getInstance().getRelative("/parent/sub2")); + String res = LinkUtil.convertLinksFromIdentifierPattern(HTML_WITH_UUIDS, LinkTransformerManager.getInstance().getRelative("/parent/sub2")); assertEquals(StringUtils.replace(HTML_WITH_ABSOLUTE_LINK, "/parent/sub.html", "sub.html"), res); } @@ -154,7 +154,7 @@ String htmlAbsoluteWithDollar = "this is a test"; String htmlUuidWithDollar = "this is a test"; - String res = LinkUtil.convertLinksFromUUIDPattern(htmlUuidWithDollar, LinkTransformerManager.getInstance().getAbsolute(false)); + String res = LinkUtil.convertLinksFromIdentifierPattern(htmlUuidWithDollar, LinkTransformerManager.getInstance().getAbsolute(false)); assertEquals(htmlAbsoluteWithDollar, res); } @@ -164,7 +164,7 @@ @Test public void testMakeUUIDFromAbsolutePath() throws LinkException { - String uuid = LinkFactory.parseLink("/parent/sub").getUUID(); + String uuid = LinkFactory.parseLink("/parent/sub").getIdentifier(); assertEquals("2", uuid); } @@ -241,7 +241,7 @@ @Test public void testMakeAbsolutePathFromUUID() throws LinkException { - String absolutePath = LinkFactory.createLink(RepositoryConstants.WEBSITE, "2").getHandle(); + String absolutePath = LinkFactory.createLink(RepositoryConstants.WEBSITE, "2").getPath(); assertEquals("/parent/sub", absolutePath); } @@ -253,8 +253,8 @@ String url = null; try { MockSession session = new MockSession("website"); - MockContent c = new MockContent((MockNode) session.getRootNode()); - url = LinkTransformerManager.getInstance().getCompleteUrl().transform(LinkFactory.createLink(c)); + MockNode node = (MockNode) session.getRootNode(); + url = LinkTransformerManager.getInstance().getCompleteUrl().transform(LinkFactory.createLink(node)); } finally { // restore serverConfiguration.setDefaultBaseUrl(base); @@ -266,7 +266,7 @@ @Test public void testCreateUndefinedLinkIfUUIDIsNonExistentOrFallbackHandleIsEmpty() { try { - String link = LinkUtil.convertLinksFromUUIDPattern("

Large article pages have a Table Of Contents

", LinkTransformerManager.getInstance().getEditorLink()); + String link = LinkUtil.convertLinksFromIdentifierPattern("

Large article pages have a Table Of Contents

", LinkTransformerManager.getInstance().getEditorLink()); assertEquals("

Large article pages have a Table Of Contents

", link); } catch (LinkException e) { fail("Got unexpected exception "+ e.getMessage()); Index: src/main/java/info/magnolia/link/Link.java =================================================================== --- src/main/java/info/magnolia/link/Link.java (revision 51040) +++ src/main/java/info/magnolia/link/Link.java (working copy) @@ -36,11 +36,19 @@ import info.magnolia.cms.beans.config.ServerConfiguration; import info.magnolia.cms.beans.runtime.File; import info.magnolia.cms.core.Content; -import info.magnolia.cms.core.ItemType; +import info.magnolia.cms.core.MgnlNodeType; import info.magnolia.cms.core.NodeData; +import info.magnolia.cms.security.AccessDeniedException; +import info.magnolia.cms.util.ContentUtil; +import info.magnolia.cms.util.NodeDataUtil; +import info.magnolia.exception.RuntimeRepositoryException; +import javax.jcr.Node; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; +import javax.jcr.ValueFormatException; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -55,18 +63,19 @@ private static final Logger log = LoggerFactory.getLogger(Link.class); - private String repository; - private String handle; - private String uuid; - private String nodeDataName; + private String workspace; + private String path; + private String identifier; + private String propertyName; private String extension; - private Content node; - private NodeData nodeData; private String fileName; - private String fallbackHandle; + private String fallbackPath; private String anchor; private String parameters; + private Node jcrNode; + private NodeData nodeData; + /** * A constructor for undefined links. (i.e linking to a nonexistent page, for instance) */ @@ -74,33 +83,56 @@ } /** - * @param content + * @deprecated since 4.5, use {@link #Link(Node)} instead. */ public Link(Content content) { - setNode(content); + this(content.getJCRNode()); + } + + /** + * @deprecated since 4.5, use {@link #Link(String, Node, Property)} instead. + */ + public Link(String repoName, Content parent, NodeData nodedata) { + setJCRNode(parent.getJCRNode()); + setWorkspace(workspace); try { - setRepository(content.getWorkspace().getName()); + setNodeData(nodedata); + setPropertyName(nodedata.getJCRProperty().getName()); } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } + } + + public Link(Node node) { + setJCRNode(node); + try { + setWorkspace(node.getSession().getWorkspace().getName()); + if (node.isNodeType(MgnlNodeType.MIX_REFERENCEABLE)) { + setIdentifier(node.getIdentifier()); + } + } catch (RepositoryException e) { throw new RuntimeException(e); } - // should we have Content.hasUUID()? ... DefaultContent hides the fact that some nodes might not have UUIDs (we can link to other content then just the one in website - if (content.isNodeType(ItemType.MIX_REFERENCEABLE)) { - setUUID(content.getUUID()); - } } - public Link(String repoName, Content parent, NodeData nodedata) { - setNode(parent); - setRepository(repoName); - setNodeData(nodedata); - setNodeDataName(nodedata.getName()); + public Link(String workspace, Node parent, Property property) { + setJCRNode(parent); + setWorkspace(workspace); + setProperty(property); + try { + setPropertyName(property.getName()); + } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } } public String getExtension() { - if(StringUtils.isEmpty(this.extension) && this.getNodeData() != null && this.getNodeData().getType() == PropertyType.BINARY){ - File binary = new File(nodeData); + if(StringUtils.isEmpty(this.extension) && getNodeData() != null && getNodeData().getType() == PropertyType.BINARY){ + //TODO fgrilli: review this. + File binary = new File(getNodeData()); extension = binary.getExtension(); } + return StringUtils.defaultIfEmpty(this.extension, ServerConfiguration.getInstance().getDefaultExtension()); } @@ -109,12 +141,12 @@ this.extension = extension; } - public String getFileName() { - if(StringUtils.isEmpty(this.fileName) && this.getNodeData() != null && this.getNodeData().getType() == PropertyType.BINARY){ - File binary = new File(nodeData); + if(StringUtils.isEmpty(this.fileName) && getNodeData() != null && getNodeData().getType() == PropertyType.BINARY){ + File binary = new File(getNodeData()); fileName = binary.getFileName(); } + return fileName; } @@ -123,76 +155,121 @@ this.fileName = fileName; } + /** + * @deprecated since 4.5, use getJCRNode() instead. + */ public Content getNode() { - return this.node; + return ContentUtil.asContent(getJCRNode()); } - + /** + * @deprecated since 4.5, use setJCRNode(Node) instead. + */ public void setNode(Content node) { - this.node = node; + setJCRNode(node.getJCRNode()); } + /** + * @deprecated since 4.5, use getProperty() instead. + */ public NodeData getNodeData() { - if(this.nodeData == null && StringUtils.isNotEmpty(this.nodeDataName) && this.getNode() != null){ - this.nodeData = this.getNode().getNodeData(this.nodeDataName); + if(this.nodeData == null && StringUtils.isNotEmpty(this.propertyName) && this.getNode() != null){ + this.nodeData = this.getNode().getNodeData(this.propertyName); } return this.nodeData; } + /** + * @deprecated since 4.5, use setProperty(Property) instead. + */ public void setNodeData(NodeData nodeData) { this.nodeData = nodeData; } + /** + * @deprecated since 4.5, use getPropertyName() instead. + */ public String getNodeDataName() { - return this.nodeDataName; + return getPropertyName(); } + /** + * @deprecated since 4.5, use setPropertyName(String) instead. + */ public void setNodeDataName(String nodeDataName) { - this.nodeDataName = nodeDataName; + setPropertyName(nodeDataName); } + public void setPropertyName(String propertyName) { + this.propertyName = propertyName; + } + + public String getPropertyName() { + return propertyName; + } + + /** + * @deprecated since 4.5, use getPath() instead. + */ public String getHandle() { - if(StringUtils.isEmpty(this.handle)){ - if(getNode() != null){ - handle = getNode().getHandle(); - } else { - handle = this.getFallbackHandle(); - } - } - return this.handle; + return getPath(); } + /** + * @deprecated since 4.5, use setPath(String) instead. + */ public void setHandle(String path) { - this.handle = path; + setPath(path); } + /** + * @deprecated since 4.5, use getWorkspace() instead. + */ public String getRepository() { - return this.repository; + return getWorkspace(); } + /** + * @deprecated since 4.5, use setWorkspace(String) instead. + */ public void setRepository(String repository) { - this.repository = repository; + setWorkspace(repository); } - + /** + * @deprecated since 4.5, use getIdentifier() instead. + */ public String getUUID() { - if(StringUtils.isEmpty(this.uuid) && this.getNode() != null){ - this.uuid = this.getNode().getUUID(); - } - return this.uuid; + return getIdentifier(); } + /** + * @deprecated since 4.5, use setIdentifier(String) instead. + */ public void setUUID(String uuid) { - this.uuid = uuid; + setIdentifier(uuid); } + /** + * @deprecated since 4.5, use getFallbackPath() instead. + */ public String getFallbackHandle() { - return this.fallbackHandle; + return getFallbackPath(); } - + /** + * @deprecated since 4.5, use setFallbackPath(String) instead. + */ public void setFallbackHandle(String fallbackPath) { - this.fallbackHandle = fallbackPath; + setFallbackPath(fallbackPath); } + public String getFallbackPath() { + return this.fallbackPath; + } + + public void setFallbackPath(String fallbackPath) { + this.fallbackPath = fallbackPath; + } + public String getAnchor() { return this.anchor; } @@ -208,4 +285,80 @@ public void setParameters(String parameters) { this.parameters = parameters; } + + public Node getJCRNode() { + return jcrNode; + } + + public void setJCRNode(Node jcrNode) { + this.jcrNode = jcrNode; + } + + public Property getProperty() { + try { + if(getNodeData() == null) { + return null; + } + return getNodeData().getJCRProperty(); + } catch (PathNotFoundException e) { + throw new RuntimeRepositoryException(e); + } + } + + public void setProperty(Property property) { + if(property == null) { + return; + } + try { + setNodeData(NodeDataUtil.getOrCreateAndSet(getNode(), property.getName(), property.getValue())); + } catch (AccessDeniedException e) { + throw new RuntimeRepositoryException(e); + } catch (ValueFormatException e) { + throw new RuntimeRepositoryException(e); + } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } + } + + public String getIdentifier() { + if(StringUtils.isEmpty(this.identifier) && this.getJCRNode() != null){ + try { + this.identifier = this.getJCRNode().getIdentifier(); + } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } + } + return this.identifier; + } + + public void setIdentifier(String id) { + this.identifier = id; + } + + public String getPath() { + if(StringUtils.isEmpty(this.path)){ + if(getJCRNode() != null) { + try { + this.path = getJCRNode().getPath(); + } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } + } else { + this.path = getFallbackPath(); + } + } + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getWorkspace() { + return this.workspace; + } + + public void setWorkspace(String workspace) { + this.workspace = workspace; + } } Index: src/main/java/info/magnolia/link/LinkUtil.java =================================================================== --- src/main/java/info/magnolia/link/LinkUtil.java (revision 51040) +++ src/main/java/info/magnolia/link/LinkUtil.java (working copy) @@ -35,9 +35,9 @@ import info.magnolia.cms.beans.config.URI2RepositoryManager; import info.magnolia.cms.core.Content; -import info.magnolia.cms.core.HierarchyManager; import info.magnolia.cms.core.NodeData; import info.magnolia.context.MgnlContext; +import info.magnolia.exception.RuntimeRepositoryException; import info.magnolia.repository.RepositoryConstants; import java.io.UnsupportedEncodingException; @@ -45,7 +45,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.jcr.Node; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; import javax.jcr.RepositoryException; +import javax.jcr.Session; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -82,27 +86,41 @@ "[^>]*" + // any attributes ">)"); // end the tag + private static final Logger log = LoggerFactory.getLogger(LinkUtil.class); + /** - * Logger. + * Transforms an identifier to a path beginning with a /. This path is used to get the page from the repository. + * The editor needs this kind of links. */ - private static final Logger log = LoggerFactory.getLogger(LinkUtil.class); + public static String convertIdentifierToPath(String identifier, String workspace) throws LinkException { + return LinkFactory.createLink(workspace, identifier).getPath(); + } + /** + * Transforms an identifier to an uri. It does not add the context path. Compared to {@link Link#getPath()}, + * this method will apply all uri to repository mappings as well as i18n. + */ + public static String convertIdentifierToURI(String identifier, String workspace) throws LinkException { + return LinkTransformerManager.getInstance().getAbsolute(false).transform(LinkFactory.createLink(workspace, identifier)); + } //-- conversions from UUID - singles /** * Transforms a uuid to a handle beginning with a /. This path is used to get the page from the repository. * The editor needs this kind of links. + * @deprecated since 4.5, use {@link #convertIdentifierToPath(String, String)} instead. */ public static String convertUUIDtoHandle(String uuid, String repository) throws LinkException { - return LinkFactory.createLink(repository, uuid).getHandle(); + return convertIdentifierToPath(uuid, repository); } /** * Transforms a uuid to an uri. It does not add the context path. In difference from {@link Link#getHandle()}, * this method will apply all uri to repository mappings as well as i18n. + * @deprecated since 4.5, use {@link #convertIdentifierToURI(String, String)} instead. */ public static String convertUUIDtoURI(String uuid, String repository) throws LinkException { - return LinkTransformerManager.getInstance().getAbsolute(false).transform(LinkFactory.createLink(repository, uuid)); + return convertIdentifierToURI(uuid, repository); } //-- conversions to UUID - bulk @@ -110,8 +128,18 @@ * Parses provided html and transforms all the links to the magnolia format. Used during storing. * @param html html code with links to be converted * @return html with changed hrefs + * @deprecated since 4.5, use {@link #convertAbsoluteLinksToIdentifiers(String)} instead. */ public static String convertAbsoluteLinksToUUIDs(String html) { + return convertAbsoluteLinksToIdentifiers(html); + } + + /** + * Parses provided html and transforms all the links to the magnolia format. Used during storing. + * @param html html code with links to be converted + * @return html with changed hrefs + */ + public static String convertAbsoluteLinksToIdentifiers(String html) { // get all link tags Matcher matcher = LINK_OR_IMAGE_PATTERN.matcher(html); StringBuffer res = new StringBuffer(); @@ -140,16 +168,15 @@ return res.toString(); } - //-- conversions from UUID - bulk - /** - * Converts provided html with links in UUID pattern format to any other kind of links based on provided link transformer. - * @param str Html with UUID links + * Converts provided html with links in identifier pattern format to any other kind of links based on provided link transformer. + * @param str Html with identifier links * @param transformer Link transformer * @return converted html with links as created by provided transformer. * @see LinkTransformerManager */ - public static String convertLinksFromUUIDPattern(String str, LinkTransformer transformer) throws LinkException { + public static String convertLinksFromIdentifierPattern(String str, LinkTransformer transformer) throws LinkException { + //TODO fgrilli: should the UUID_PATTERN now have an identifier? Matcher matcher = LinkFactory.UUID_PATTERN.matcher(str); StringBuffer res = new StringBuffer(); while (matcher.find()) { @@ -164,11 +191,30 @@ return res.toString(); } - public static String convertLinksFromUUIDPattern(String str) throws LinkException { + public static String convertLinksFromIdentifierPattern(String str) throws LinkException { LinkTransformer transformer = LinkTransformerManager.getInstance().getBrowserLink(null); - return convertLinksFromUUIDPattern(str, transformer); + return convertLinksFromIdentifierPattern(str, transformer); } + /** + * Converts provided html with links in UUID pattern format to any other kind of links based on provided link transformer. + * @param str Html with UUID links + * @param transformer Link transformer + * @return converted html with links as created by provided transformer. + * @see LinkTransformerManager + * @deprecated since 4.5, use {@link #convertLinksFromIdentifierPattern(String, LinkTransformer)} instead. + */ + public static String convertLinksFromUUIDPattern(String str, LinkTransformer transformer) throws LinkException { + return convertLinksFromIdentifierPattern(str, transformer); + } + + /** + * @deprecated since 4.5, use {@link #convertLinksFromIdentifierPattern(String)} instead. + */ + public static String convertLinksFromUUIDPattern(String str) throws LinkException { + return convertLinksFromIdentifierPattern(str); + } + /** * Determines if the given link is internal and relative. */ public static boolean isInternalRelativeLink(String href) { @@ -257,24 +303,30 @@ * @param nodedata Node data to create link for. * @return Absolute link to the provided node data. * @see AbstractI18nContentSupport + * + * @deprecated since 4.5, use {@link #createAbsoluteLink(Property)} instead. */ public static String createAbsoluteLink(NodeData nodedata) throws LinkException { if(nodedata == null || !nodedata.isExist()){ return null; } - return LinkTransformerManager.getInstance().getAbsolute().transform(LinkFactory.createLink(nodedata)); + try { + return createAbsoluteLink(nodedata.getJCRProperty()); + } catch (PathNotFoundException e) { + throw new LinkException(e); + } } /** * Creates absolute link including context path to the provided content and performing all URI2Repository mappings and applying locales. - * @param uuid UUID of content to create link to. - * @param repository Name of the repository where content is located. + * @param id UUID of content to create link to. + * @param workspace Name of the workspace where content is located. * @return Absolute link to the provided content. * @see AbstractI18nContentSupport */ - public static String createAbsoluteLink(String repository, String uuid) throws RepositoryException { - HierarchyManager hm = MgnlContext.getHierarchyManager(repository); - Content node = hm.getContentByUUID(uuid); + public static String createAbsoluteLink(String workspace, String id) throws RepositoryException { + Session session = MgnlContext.getJCRSession(workspace); + Node node = session.getNodeByIdentifier(id); return createAbsoluteLink(node); } @@ -283,24 +335,25 @@ * @param content content to create link to. * @return Absolute link to the provided content. * @see AbstractI18nContentSupport + * @deprecated since 4.5, use {@link #createAbsoluteLink(Node)} instead. */ public static String createAbsoluteLink(Content content) { if(content == null){ return null; } - return LinkTransformerManager.getInstance().getAbsolute().transform(LinkFactory.createLink(content)); + return createAbsoluteLink(content.getJCRNode()); } /** * Creates a complete url to access given content from external systems applying all the URI2Repository mappings and locales. - * @param content - * @return + * @deprecated since 4.5, use {@link #createExternalLink(Node)} instead. + * */ public static String createExternalLink(Content content) { if(content == null){ return null; } - return LinkTransformerManager.getInstance().getCompleteUrl().transform(LinkFactory.createLink(content)); + return createExternalLink(content.getJCRNode()); } /** @@ -308,12 +361,13 @@ * @param nodedata Node data to create link for. * @return Absolute link to the provided node data. * @see AbstractI18nContentSupport + * @deprecated since 4.5, use {@link #createLink(Node)} instead. */ public static String createLink(Content node) { if(node == null){ return null; } - return LinkTransformerManager.getInstance().getBrowserLink(node.getHandle()).transform(LinkFactory.createLink(node)); + return createLink(node.getJCRNode()); } /** @@ -321,28 +375,102 @@ * @param nodedata Node data to create link for. * @return Absolute link to the provided node data. * @see AbstractI18nContentSupport + * + * @deprecated since 4.5, use {@link #createLink(Property)} instead. */ public static String createLink(NodeData nodedata) throws LinkException { if(nodedata == null || !nodedata.isExist()){ return null; } try { - return LinkTransformerManager.getInstance().getBrowserLink(nodedata.getParent().getHandle()).transform(LinkFactory.createLink(nodedata)); + return createLink(nodedata.getJCRProperty()); } catch (RepositoryException e) { throw new LinkException(e.getMessage(), e); } } /** + * Creates absolute link including context path for the provided property. + * @param property Property to create link for. + * @return Absolute link to the provided node data. + * @see AbstractI18nContentSupport + */ + public static String createAbsoluteLink(Property property) throws LinkException { + if(property == null){ + return null; + } + return LinkTransformerManager.getInstance().getAbsolute().transform(LinkFactory.createLink(property)); + } + + + /** + * Creates absolute link including context path to the provided node and performing all URI2Repository mappings and applying locales. + * @param content content to create link to. + * @return Absolute link to the provided node. + * @see AbstractI18nContentSupport + */ + public static String createAbsoluteLink(Node node) { + if(node == null){ + return null; + } + return LinkTransformerManager.getInstance().getAbsolute().transform(LinkFactory.createLink(node)); + } + + /** + * Creates a complete url to access given node from external systems applying all the URI2Repository mappings and locales. + * @param node + */ + public static String createExternalLink(Node node) { + if(node == null){ + return null; + } + return LinkTransformerManager.getInstance().getCompleteUrl().transform(LinkFactory.createLink(node)); + } + + /** + * Creates link guessing best possible link format from current site and provided node. + * @param node Node to create link for. + * @return Absolute link to the provided node data. + * @see AbstractI18nContentSupport + */ + public static String createLink(Node node) { + if(node == null){ + return null; + } + try { + return LinkTransformerManager.getInstance().getBrowserLink(node.getPath()).transform(LinkFactory.createLink(node)); + } catch (RepositoryException e) { + throw new RuntimeRepositoryException(e); + } + } + + /** + * Creates link guessing best possible link format from current site and the provided property. + * @param property Property to create link for. + * @return Absolute link to the provided property. + * @see AbstractI18nContentSupport + */ + public static String createLink(Property property) throws LinkException { + if(property == null){ + return null; + } + try { + return LinkTransformerManager.getInstance().getBrowserLink(property.getParent().getPath()).transform(LinkFactory.createLink(property)); + } catch (RepositoryException e) { + throw new LinkException(e.getMessage(), e); + } + } + + /** * Creates link guessing best possible link format from current site and provided content. - * @param uuid UUID of content to create link to. + * @param id identifier of content to create link to. * @param repository Name of the repository where content is located. * @return Absolute link to the provided content. * @see AbstractI18nContentSupport */ - public static String createLink(String repository, String uuid) throws RepositoryException { - HierarchyManager hm = MgnlContext.getHierarchyManager(repository); - Content node = hm.getContentByUUID(uuid); + public static String createLink(String workspace, String id) throws RepositoryException { + Session session = MgnlContext.getJCRSession(workspace); + Node node = session.getNodeByIdentifier(id); return createLink(node); } } Index: src/test/java/info/magnolia/link/UUIDLinkTest.java =================================================================== --- src/test/java/info/magnolia/link/UUIDLinkTest.java (revision 51040) +++ src/test/java/info/magnolia/link/UUIDLinkTest.java (working copy) @@ -33,11 +33,13 @@ */ package info.magnolia.link; -import static org.easymock.classextension.EasyMock.*; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; import static org.junit.Assert.assertEquals; -import info.magnolia.cms.util.ContentUtil; + +import info.magnolia.jcr.util.SessionUtil; import info.magnolia.repository.RepositoryConstants; -import info.magnolia.test.mock.MockContent; +import info.magnolia.test.mock.jcr.MockNode; import java.text.MessageFormat; @@ -89,8 +91,8 @@ public void testParseLink() throws Exception { Link link = LinkFactory.parseLink(HREF_ABSOLUTE_LINK); - assertEquals(RepositoryConstants.WEBSITE, link.getRepository()); - assertEquals(HANDLE_PARENT_SUB, link.getHandle()); + assertEquals(RepositoryConstants.WEBSITE, link.getWorkspace()); + assertEquals(HANDLE_PARENT_SUB, link.getPath()); assertEquals(UUID_PATTERN_SIMPLE, LinkFactory.toPattern(link)); } @@ -123,7 +125,7 @@ @Test public void testUUIDToAbsoluteLinksAfterRenaming() throws Exception{ - ((MockContent)ContentUtil.getContent(RepositoryConstants.WEBSITE, "/parent/sub")).setName("subRenamed"); + ((MockNode)SessionUtil.getNode(RepositoryConstants.WEBSITE, "/parent/sub")).setName("subRenamed"); Link link = LinkFactory.parseUUIDLink(UUID_PATTERN_SIMPLE); assertEquals("/parent/subRenamed.html", NOP_TRANSFORMER.transform(link)); } @@ -142,7 +144,7 @@ @Test public void testUUIDToBinaryAfterRenaming() throws Exception { // now rename the the page - ((MockContent)ContentUtil.getContent(RepositoryConstants.WEBSITE, "/parent/sub")).setName("subRenamed"); + ((MockNode)SessionUtil.getNode(RepositoryConstants.WEBSITE, "/parent/sub")).setName("subRenamed"); Link link = LinkFactory.parseUUIDLink(UUID_PATTERN_BINARY); assertEquals(StringUtils.replace(HREF_BINARY, "sub", "subRenamed"), NOP_TRANSFORMER.transform(link));