001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.lenya.cms.linking;
019:
020: import org.apache.avalon.framework.container.ContainerUtil;
021: import org.apache.avalon.framework.logger.AbstractLogEnabled;
022: import org.apache.avalon.framework.logger.Logger;
023: import org.apache.avalon.framework.service.ServiceException;
024: import org.apache.avalon.framework.service.ServiceManager;
025: import org.apache.lenya.cms.cocoon.components.context.ContextUtility;
026: import org.apache.lenya.cms.publication.Document;
027: import org.apache.lenya.cms.publication.Publication;
028: import org.apache.lenya.cms.publication.ResourceType;
029: import org.apache.lenya.xml.DocumentHelper;
030: import org.apache.xpath.XPathAPI;
031: import org.w3c.dom.Attr;
032: import org.w3c.dom.Node;
033: import org.w3c.dom.NodeList;
034:
035: /**
036: * Utility class to convert <code>lenya-document:</code> links from and to URL
037: * links.
038: */
039: public class LinkConverter extends AbstractLogEnabled {
040:
041: private ServiceManager manager;
042:
043: /**
044: * Creates a link converter.
045: * @param manager The service manager.
046: * @param logger The logger.
047: */
048: public LinkConverter(ServiceManager manager, Logger logger) {
049: ContainerUtil.enableLogging(this , logger);
050: this .manager = manager;
051: }
052:
053: /**
054: * Converts all URL-based links to UUID-based links.
055: * @param doc The document to convert.
056: * @param useContextPath If the request's context path should be considered.
057: */
058: public void convertUrlsToUuids(Document doc, boolean useContextPath) {
059: convertUrlsToUuids(doc.getPublication(), doc, useContextPath);
060: }
061:
062: /**
063: * Converts all URL-based links to UUID-based links. The link URLs can
064: * originate from a different publication.
065: * @param srcPub The publication where the content comes from.
066: * @param examinedDocument The document in the target publication.
067: * @param useContextPath If the request's context path should be considered.
068: */
069: public void convertUrlsToUuids(Publication srcPub,
070: Document examinedDocument, boolean useContextPath) {
071: boolean linksRewritten = false;
072: try {
073:
074: String prefix = useContextPath ? getContextPath() : "";
075:
076: ResourceType type = examinedDocument.getResourceType();
077: String[] xPaths = type.getLinkAttributeXPaths();
078:
079: if (xPaths.length == 0) {
080: if (getLogger().isDebugEnabled()) {
081: getLogger().debug(
082: "Convert links: No XPaths for resource type ["
083: + type.getName() + "]");
084: }
085: } else {
086: Publication pub = examinedDocument.getPublication();
087: LinkRewriter incomingRewriter = new IncomingLinkRewriter(
088: pub);
089: LinkRewriter urlToUuidRewriter = new UrlToUuidRewriter(
090: examinedDocument.area());
091:
092: org.w3c.dom.Document xml = DocumentHelper
093: .readDocument(examinedDocument.getInputStream());
094:
095: for (int xPathIndex = 0; xPathIndex < xPaths.length; xPathIndex++) {
096: if (getLogger().isDebugEnabled()) {
097: getLogger().debug(
098: "Convert links: Check XPath ["
099: + xPaths[xPathIndex] + "]");
100: }
101: NodeList nodes = XPathAPI.selectNodeList(xml,
102: xPaths[xPathIndex]);
103: for (int nodeIndex = 0; nodeIndex < nodes
104: .getLength(); nodeIndex++) {
105: Node node = nodes.item(nodeIndex);
106: if (node.getNodeType() != Node.ATTRIBUTE_NODE) {
107: throw new RuntimeException(
108: "The XPath ["
109: + xPaths[xPathIndex]
110: + "] may only match attribute nodes!");
111: }
112: Attr attribute = (Attr) node;
113: final String url = attribute.getValue();
114: if (getLogger().isDebugEnabled()) {
115: getLogger().debug(
116: "Convert links: Check URL [" + url
117: + "]");
118: }
119: final String originalUrl = url
120: .startsWith(prefix) ? url
121: .substring(prefix.length()) : url;
122: final String srcPubUrl;
123: if (incomingRewriter.matches(originalUrl)) {
124: srcPubUrl = incomingRewriter
125: .rewrite(originalUrl);
126: } else {
127: srcPubUrl = originalUrl;
128: }
129: final String srcPubPrefix = "/"
130: + srcPub.getId() + "/";
131: if (srcPubUrl.startsWith(srcPubPrefix)) {
132: final String destPubUrl = "/"
133: + pub.getId()
134: + "/"
135: + srcPubUrl.substring(srcPubPrefix
136: .length());
137: if (urlToUuidRewriter.matches(destPubUrl)) {
138: String rewrittenUrl = urlToUuidRewriter
139: .rewrite(destPubUrl);
140: attribute.setValue(rewrittenUrl);
141: linksRewritten = true;
142: }
143: }
144: }
145: }
146:
147: if (linksRewritten) {
148: DocumentHelper.writeDocument(xml, examinedDocument
149: .getOutputStream());
150: }
151: }
152: } catch (Exception e) {
153: throw new RuntimeException("Error rewriting document: ["
154: + examinedDocument + "]", e);
155: }
156: }
157:
158: protected String getContextPath() throws ServiceException {
159: String prefix;
160: ContextUtility ctxUtil = null;
161: try {
162: ctxUtil = (ContextUtility) this.manager
163: .lookup(ContextUtility.ROLE);
164: prefix = ctxUtil.getRequest().getContextPath();
165: } finally {
166: if (ctxUtil != null) {
167: this.manager.release(ctxUtil);
168: }
169: }
170: return prefix;
171: }
172:
173: }
|