You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by an...@apache.org on 2006/11/09 18:16:16 UTC

svn commit: r472981 - in /lenya/trunk/src: java/org/apache/lenya/cms/cocoon/transformation/ java/org/apache/lenya/util/ modules-core/linking/ modules-core/linking/config/ modules-core/linking/config/cocoon-xconf/ modules-core/linking/java/ modules-core...

Author: andreas
Date: Thu Nov  9 09:16:14 2006
New Revision: 472981

URL: http://svn.apache.org/viewvc?view=rev&rev=472981
Log:
Add linking module, use lenya-document link syntax in BXE

Added:
    lenya/trunk/src/java/org/apache/lenya/util/Query.java
    lenya/trunk/src/modules-core/linking/
    lenya/trunk/src/modules-core/linking/config/
    lenya/trunk/src/modules-core/linking/config/cocoon-xconf/
    lenya/trunk/src/modules-core/linking/config/cocoon-xconf/linkresolver.xconf
    lenya/trunk/src/modules-core/linking/config/cocoon-xconf/sourcefactory.xconf
    lenya/trunk/src/modules-core/linking/java/
    lenya/trunk/src/modules-core/linking/java/src/
    lenya/trunk/src/modules-core/linking/java/src/org/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/source/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/source/DocumentSourceFactory.java
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/transformation/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/transformation/LinkRewritingTransformer.java
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolver.java
    lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolverImpl.java
    lenya/trunk/src/modules-core/linking/module.xml
Removed:
    lenya/trunk/src/java/org/apache/lenya/cms/cocoon/transformation/LinkRewritingTransformer.java
Modified:
    lenya/trunk/src/modules/bxe/resources/javascript/insertLink.js
    lenya/trunk/src/modules/bxe/xslt/link.xsl
    lenya/trunk/src/modules/sitetree/resources/javascript/navtree.js
    lenya/trunk/src/modules/xhtml/sitemap.xmap

Added: lenya/trunk/src/java/org/apache/lenya/util/Query.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/java/org/apache/lenya/util/Query.java?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/java/org/apache/lenya/util/Query.java (added)
+++ lenya/trunk/src/java/org/apache/lenya/util/Query.java Thu Nov  9 09:16:14 2006
@@ -0,0 +1,100 @@
+/*
+ * Copyright  1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.lenya.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ * Utility class to analyze a query string of the form
+ * <code>key1=value1&key2=value2&...</code>.
+ * </p>
+ * <p>
+ * Invalid parts (not a valid key-value-pair) are omitted.
+ * </p>
+ */
+public class Query {
+
+    protected static final String PAIR_DELIMITER = "&";
+    protected static final String KEY_VALUE_DELIMITER = "=";
+    private String string;
+    private String pairDelimiter;
+    private String keyValueDelimiter;
+
+    /**
+     * Creates a query object with default values for the pair and key-value
+     * delimiters.
+     * 
+     * @param string The query string.
+     */
+    public Query(String string) {
+        this(string, PAIR_DELIMITER, KEY_VALUE_DELIMITER);
+    }
+
+    /**
+     * Creates a query object.
+     * @param string The string.
+     * @param pairDelimiter The delimiter between key-value pairs.
+     * @param keyValueDelimiter The delimiter between key and value.
+     */
+    public Query(String string, String pairDelimiter, String keyValueDelimiter) {
+        this.string = string;
+        this.pairDelimiter = pairDelimiter;
+        this.keyValueDelimiter = keyValueDelimiter;
+    }
+
+    private Map key2value;
+
+    protected void analyze() {
+        if (this.key2value == null) {
+            this.key2value = new HashMap();
+            String[] pairs = this.string.split(getPairDelimiter());
+            for (int i = 0; i < pairs.length; i++) {
+                String[] keyAndValue = pairs[i].split(getKeyValueDelimiter());
+                if (keyAndValue.length == 2) {
+                    final String key = keyAndValue[0];
+                    final String value = keyAndValue[1];
+                    this.key2value.put(key, value);
+                }
+            }
+        }
+    }
+
+    public String getValue(String key) {
+        analyze();
+        return (String) this.key2value.get(key);
+    }
+
+    public String getValue(String key, String defaultValue) {
+        String value = getValue(key);
+        if (value == null) {
+            return defaultValue;
+        } else {
+            return value;
+        }
+    }
+
+    public String getKeyValueDelimiter() {
+        return keyValueDelimiter;
+    }
+
+    public String getPairDelimiter() {
+        return pairDelimiter;
+    }
+
+}

Added: lenya/trunk/src/modules-core/linking/config/cocoon-xconf/linkresolver.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/config/cocoon-xconf/linkresolver.xconf?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/config/cocoon-xconf/linkresolver.xconf (added)
+++ lenya/trunk/src/modules-core/linking/config/cocoon-xconf/linkresolver.xconf Thu Nov  9 09:16:14 2006
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<!-- $Id:$ -->
+
+<xconf xpath="/cocoon" unless="/cocoon/component[@role = 'org.apache.lenya.cms.linking.LinkResolver']">
+
+  <component logger="" role="org.apache.lenya.cms.linking.LinkResolver"
+    class="org.apache.lenya.cms.linking.LinkResolverImpl"/>
+  
+</xconf>

Added: lenya/trunk/src/modules-core/linking/config/cocoon-xconf/sourcefactory.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/config/cocoon-xconf/sourcefactory.xconf?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/config/cocoon-xconf/sourcefactory.xconf (added)
+++ lenya/trunk/src/modules-core/linking/config/cocoon-xconf/sourcefactory.xconf Thu Nov  9 09:16:14 2006
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<!-- $Id:$ -->
+
+<xconf xpath="/cocoon/source-factories" unless="/cocoon/source-factories/component-instance[@name = 'lenya-document']">
+
+  <component-instance logger="" name="lenya-document"
+    class="org.apache.lenya.cms.cocoon.source.DocumentSourceFactory"/>
+  
+</xconf>

Added: lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/source/DocumentSourceFactory.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/source/DocumentSourceFactory.java?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/source/DocumentSourceFactory.java (added)
+++ lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/source/DocumentSourceFactory.java Thu Nov  9 09:16:14 2006
@@ -0,0 +1,177 @@
+/*
+ * Copyright  1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.lenya.cms.cocoon.source;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceException;
+import org.apache.excalibur.source.SourceFactory;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.lenya.cms.linking.LinkResolver;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.DocumentException;
+import org.apache.lenya.cms.publication.DocumentFactory;
+import org.apache.lenya.cms.publication.DocumentUtil;
+import org.apache.lenya.cms.repository.RepositoryUtil;
+import org.apache.lenya.cms.repository.Session;
+import org.apache.lenya.util.Query;
+import org.apache.lenya.util.ServletHelper;
+
+/**
+ * <p>
+ * This source factory allows to access documents using their
+ * </p>
+ * <ul>
+ * <li>publication ID</li>
+ * <li>area</li>
+ * <li>UUID</li>
+ * <li>language</li>
+ * <li>revision number</li>
+ * </ul>
+ * <p>
+ * Additional parameters:
+ * </p>
+ * <ul>
+ * <li><strong>format</strong> - the resource type format</li>
+ * </ul>
+ * <p>
+ * All of these parameters are optional and default to the attributes of the
+ * document which contains the link.
+ * </p>
+ * <p>
+ * Syntax (square brackets denote optional parts):
+ * </p>
+ * <code>lenya-document:&lt;uuid&gt;[,lang=...][,area=...][,rev=...][,pub=...]</code>
+ */
+public class DocumentSourceFactory extends AbstractLogEnabled implements SourceFactory, ThreadSafe,
+        Contextualizable, Serviceable, Configurable {
+
+    public static final String SCHEME = "lenya-document";
+
+    private Context context;
+    private ServiceManager manager;
+
+    /**
+     * Used for resolving the object model.
+     * 
+     * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
+     */
+    public void contextualize(Context context) throws ContextException {
+        this.context = context;
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+     */
+    public void service(ServiceManager manager) throws ServiceException {
+        this.manager = manager;
+    }
+
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
+     */
+    public void configure(Configuration configuration) throws ConfigurationException {
+    }
+
+    /**
+     * @see org.apache.excalibur.source.SourceFactory#getSource(java.lang.String,
+     *      java.util.Map)
+     */
+    public Source getSource(String location, Map parameters) throws MalformedURLException,
+            IOException, SourceException {
+
+        Map objectModel = ContextHelper.getObjectModel(this.context);
+        Request request = ObjectModelHelper.getRequest(objectModel);
+
+        String[] uriAndQuery = location.split("\\?");
+
+        String linkUri = uriAndQuery[0];
+        String queryString = null;
+        if (uriAndQuery.length > 1) {
+            queryString = uriAndQuery[1];
+        }
+
+        LinkResolver resolver = null;
+        try {
+            resolver = (LinkResolver) this.manager.lookup(LinkResolver.ROLE);
+            DocumentFactory factory = DocumentUtil.getDocumentFactory(this.manager, request);
+            String webappUrl = ServletHelper.getWebappURI(request);
+            Document currentDoc = factory.getFromURL(webappUrl);
+
+            Document doc = resolver.resolve(currentDoc, linkUri);
+
+            String format = null;
+            if (queryString != null) {
+                Query query = new Query(queryString);
+                format = query.getValue("format");
+            }
+            if (format != null) {
+                return getFormatSource(doc, format);
+            } else {
+                String lenyaURL = doc.getSourceURI();
+                Session session = RepositoryUtil.getSession(this.manager, request);
+                return new RepositorySource(manager, lenyaURL, session, getLogger());
+            }
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    protected Source getFormatSource(Document doc, String format) throws DocumentException,
+            ServiceException, IOException {
+        String formatBaseUri = doc.getResourceType().getFormatURI(format);
+        String formatUri = formatBaseUri + "/" + doc.getPublication().getId() + "/" + doc.getArea()
+                + "/" + doc.getUUID() + "/" + doc.getLanguage();
+
+        SourceResolver resolver = null;
+        try {
+            resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
+            return resolver.resolveURI(formatUri);
+        } finally {
+            if (resolver != null) {
+                this.manager.release(resolver);
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.excalibur.source.SourceFactory#release(org.apache.excalibur.source.Source)
+     */
+    public void release(Source source) {
+        // Source will be released by delegated source factory.
+    }
+
+}

Added: lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/transformation/LinkRewritingTransformer.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/transformation/LinkRewritingTransformer.java?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/transformation/LinkRewritingTransformer.java (added)
+++ lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/cocoon/transformation/LinkRewritingTransformer.java Thu Nov  9 09:16:14 2006
@@ -0,0 +1,434 @@
+/*
+ * Copyright  1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.lenya.cms.cocoon.transformation;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceSelector;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.transformation.AbstractSAXTransformer;
+import org.apache.lenya.ac.AccessControlException;
+import org.apache.lenya.ac.AccessController;
+import org.apache.lenya.ac.AccessControllerResolver;
+import org.apache.lenya.ac.AccreditableManager;
+import org.apache.lenya.ac.Policy;
+import org.apache.lenya.ac.PolicyManager;
+import org.apache.lenya.cms.linking.LinkResolver;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.DocumentFactory;
+import org.apache.lenya.cms.publication.DocumentUtil;
+import org.apache.lenya.cms.publication.Proxy;
+import org.apache.lenya.cms.publication.Publication;
+import org.apache.lenya.cms.repository.RepositoryUtil;
+import org.apache.lenya.cms.repository.Session;
+import org.apache.lenya.util.ServletHelper;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * <p>
+ * Link rewriting transformer.
+ * </p>
+ * 
+ * <p>
+ * This transformer is applied to an XHMTL document. It processes
+ * <code>&lt;xhtml:a href="..."&gt;</code> attributes of the following form:
+ * </p>
+ * <p>
+ * <code>/{publication-id}/{area}{document-url}</code>
+ * </p>
+ * <p>
+ * These links are rewritten using the following rules:
+ * </p>
+ * <ul>
+ * <li>The area is replaced by the current area (obtained from the page envelope).</li>
+ * <li>A URL prefix is added depending on the proxy configuration of the publication.</li>
+ * <li>If the target document does not exist and is in the authoring area, the href attribute is
+ * removed and a class="brokenlink" attribute is added to the <code>&lt;a/&gt;</code> element</li>
+ * <li>If the target document does not exist and is in the live area, the <code>&lt;a/&gt;</code>
+ * element is removed to disable the link.</li>
+ * </ul>
+ * 
+ * $Id: LinkRewritingTransformer.java,v 1.7 2004/03/16 11:12:16 gregor
+ */
+public class LinkRewritingTransformer extends AbstractSAXTransformer implements Disposable {
+
+    protected static final String BROKEN_ATTRIB = "class";
+    protected static final String BROKEN_VALUE = "brokenlink";
+
+    private boolean ignoreAElement = false;
+    private ServiceSelector serviceSelector;
+    private PolicyManager policyManager;
+    private AccessControllerResolver acResolver;
+    private AccreditableManager accreditableManager;
+
+    private Document currentDocument;
+
+    private DocumentFactory factory;
+    private LinkResolver linkResolver;
+
+    /**
+     * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver,
+     *      java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
+     */
+    public void setup(SourceResolver _resolver, Map _objectModel, String _source,
+            Parameters _parameters) throws ProcessingException, SAXException, IOException {
+        super.setup(_resolver, _objectModel, _source, _parameters);
+
+        Request _request = ObjectModelHelper.getRequest(_objectModel);
+
+        try {
+            Session session = RepositoryUtil.getSession(this.manager, _request);
+            this.factory = DocumentUtil.createDocumentFactory(this.manager, session);
+            String url = ServletHelper.getWebappURI(_request);
+            this.currentDocument = this.factory.getFromURL(url);
+        } catch (final Exception e1) {
+            throw new ProcessingException(e1);
+        }
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Setting up transformer");
+            getLogger().debug("    Processed version:       [" + getCurrentDocument() + "]");
+        }
+
+        this.serviceSelector = null;
+        this.acResolver = null;
+        this.policyManager = null;
+        this.linkResolver = null;
+
+        try {
+            this.serviceSelector = (ServiceSelector) this.manager.lookup(AccessControllerResolver.ROLE
+                    + "Selector");
+            this.acResolver = (AccessControllerResolver) this.serviceSelector.select(AccessControllerResolver.DEFAULT_RESOLVER);
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("    Resolved AC resolver [" + this.acResolver + "]");
+            }
+            String webappUrl = ServletHelper.getWebappURI(_request);
+            AccessController accessController = this.acResolver.resolveAccessController(webappUrl);
+            this.accreditableManager = accessController.getAccreditableManager();
+            this.policyManager = accessController.getPolicyManager();
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("    Using policy manager [" + this.policyManager + "]");
+            }
+            this.linkResolver = (LinkResolver) this.manager.lookup(LinkResolver.ROLE);
+        } catch (final ServiceException e) {
+            throw new ProcessingException(e);
+        } catch (final AccessControlException e) {
+            throw new ProcessingException(e);
+        }
+    }
+
+    /**
+     * Returns the currently processed document.
+     * @return A document.
+     */
+    protected Document getCurrentDocument() {
+        return this.currentDocument;
+    }
+
+    /**
+     * The local name of the HTML &lt;a&gt; href attribute.
+     */
+    public static final String ATTRIBUTE_HREF = "href";
+
+    private String indent = "";
+
+    /**
+     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
+     *      java.lang.String, org.xml.sax.Attributes)
+     */
+    public void startElement(String uri, String name, String qname, Attributes attrs)
+            throws SAXException {
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug(this.indent + "<" + qname + "> (ignoreAElement = "
+                    + this.ignoreAElement + ")");
+            this.indent += "  ";
+        }
+
+        AttributesImpl newAttrs = null;
+        if (lookingAtAElement(name)) {
+
+            this.ignoreAElement = false;
+
+            String href = attrs.getValue(ATTRIBUTE_HREF);
+            if (href != null) {
+
+                Publication publication = getCurrentDocument().getPublication();
+
+                try {
+                    newAttrs = new AttributesImpl(attrs);
+
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug(this.indent + "href URL: [" + href + "]");
+                    }
+                    
+                    if (href.startsWith("lenya-document:")) {
+                        
+                        String anchor = null;
+                        String url = null;
+
+                        int anchorIndex = href.indexOf("#");
+                        if (anchorIndex > -1) {
+                            url = href.substring(0, anchorIndex);
+                            anchor = href.substring(anchorIndex + 1);
+                        } else {
+                            url = href;
+                        }
+                        
+                        String[] linkUriAndQuery = url.split("\\?");
+                        String linkUri = linkUriAndQuery[0];
+                        String queryString = null;
+                        if (linkUriAndQuery.length > 1) {
+                            queryString = linkUriAndQuery[1];
+                        }
+                        Document targetDocument = this.linkResolver.resolve(getCurrentDocument(), linkUri);
+                        String extension = targetDocument.getExtension();
+                        if (extension.length() > 0) {
+                            extension = "." + extension;
+                        }
+                        rewriteLink(newAttrs,
+                                targetDocument,
+                                anchor,
+                                queryString,
+                                extension);
+                    }
+                    else if (href.startsWith("/" + publication.getId())) {
+
+                        final String webappUrlWithQueryString = href;
+                        String webappUrlWithAnchor;
+
+                        String queryString = null;
+                        int queryStringIndex = webappUrlWithQueryString.indexOf("?");
+                        if (queryStringIndex > -1) {
+                            webappUrlWithAnchor = webappUrlWithQueryString.substring(0,
+                                    queryStringIndex);
+                            queryString = webappUrlWithQueryString.substring(queryStringIndex + 1);
+                        } else {
+                            webappUrlWithAnchor = webappUrlWithQueryString;
+                        }
+
+                        String anchor = null;
+                        String webappUrl = null;
+
+                        int anchorIndex = webappUrlWithAnchor.indexOf("#");
+                        if (anchorIndex > -1) {
+                            webappUrl = webappUrlWithAnchor.substring(0, anchorIndex);
+                            anchor = webappUrlWithAnchor.substring(anchorIndex + 1);
+                        } else {
+                            webappUrl = webappUrlWithAnchor;
+                        }
+
+                        if (getLogger().isDebugEnabled()) {
+                            getLogger().debug(this.indent + "webapp URL: [" + webappUrl + "]");
+                            getLogger().debug(this.indent + "anchor:     [" + anchor + "]");
+                        }
+                        if (this.factory.isDocument(webappUrl)) {
+
+                            Document targetDocument = this.factory.getFromURL(webappUrl);
+
+                            if (getLogger().isDebugEnabled()) {
+                                getLogger().debug(this.indent + "Resolved target document: ["
+                                        + targetDocument + "]");
+                            }
+
+                            targetDocument = this.factory.get(publication,
+                                    getCurrentDocument().getArea(),
+                                    targetDocument.getUUID(),
+                                    targetDocument.getLanguage());
+
+                            if (targetDocument.hasLink()) {
+                                String extension = "";
+                                int lastDotIndex = webappUrl.lastIndexOf(".");
+                                if (lastDotIndex > -1) {
+                                    extension = webappUrl.substring(lastDotIndex);
+                                }
+                                rewriteLink(newAttrs,
+                                        targetDocument,
+                                        anchor,
+                                        queryString,
+                                        extension);
+                            } else if (getCurrentDocument().getArea()
+                                    .equals(Publication.AUTHORING_AREA)) {
+                                markBrokenLink(newAttrs, href);
+                            } else {
+                                this.ignoreAElement = true;
+                            }
+                        }
+                    }
+                } catch (final Exception e) {
+                    getLogger().error("startElement failed: ", e);
+                    throw new SAXException(e);
+                }
+            }
+
+        }
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug(this.indent + "ignoreAElement: " + this.ignoreAElement);
+        }
+
+        if (!(lookingAtAElement(name) && this.ignoreAElement)) {
+            if (newAttrs != null) {
+                attrs = newAttrs;
+            }
+            super.startElement(uri, name, qname, attrs);
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug(this.indent + "<" + qname + "> sent");
+            }
+        }
+    }
+
+    /**
+     * Marks a <code>&lt;a/&gt;</code> element as broken and removes href attribute.
+     * 
+     * @param newAttrs The new attributes.
+     * @throws AccessControlException when something went wrong.
+     */
+    protected void markBrokenLink(AttributesImpl newAttrs, String brokenHref)
+            throws AccessControlException {
+        if (newAttrs.getIndex(BROKEN_ATTRIB) > -1)
+            newAttrs.removeAttribute(newAttrs.getIndex(BROKEN_ATTRIB));
+        if (newAttrs.getIndex("title") > -1)
+            newAttrs.removeAttribute(newAttrs.getIndex("title"));
+        if (newAttrs.getIndex("href") > -1)
+            newAttrs.setAttribute(newAttrs.getIndex("href"), "", "href", "href", "CDATA", "");
+        String warning = "Broken Link: " + brokenHref;
+        newAttrs.addAttribute("", "title", "title", "CDATA", warning);
+        newAttrs.addAttribute("", BROKEN_ATTRIB, BROKEN_ATTRIB, "CDATA", BROKEN_VALUE);
+    }
+
+    /**
+     * Rewrites a link.
+     * 
+     * @param newAttrs The new attributes.
+     * @param targetDocument The target document.
+     * @param anchor The anchor (the string after the # character in the URL).
+     * @param queryString The query string without question mark.
+     * @param extension The extension to use.
+     * @throws AccessControlException when something went wrong.
+     */
+    protected void rewriteLink(AttributesImpl newAttrs, Document targetDocument, String anchor,
+            String queryString, String extension) throws AccessControlException {
+
+        String webappUrl = targetDocument.getCanonicalWebappURL();
+        Policy policy = this.policyManager.getPolicy(this.accreditableManager, webappUrl);
+
+        Proxy proxy = targetDocument.getPublication().getProxy(targetDocument,
+                policy.isSSLProtected());
+
+        String rewrittenURL;
+        if (proxy == null) {
+            rewrittenURL = this.request.getContextPath() + webappUrl;
+        } else {
+            rewrittenURL = proxy.getURL(targetDocument);
+        }
+
+        int lastDotIndex = rewrittenURL.lastIndexOf(".");
+        if (lastDotIndex > -1) {
+            rewrittenURL = rewrittenURL.substring(0, lastDotIndex) + extension;
+        }
+
+        if (anchor != null) {
+            rewrittenURL += "#" + anchor;
+        }
+
+        if (queryString != null) {
+            rewrittenURL += "?" + queryString;
+        }
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug(this.indent + "SSL protection: [" + policy.isSSLProtected() + "]");
+            getLogger().debug(this.indent + "Resolved proxy: [" + proxy + "]");
+            getLogger().debug(this.indent + "Rewriting URL to: [" + rewrittenURL + "]");
+        }
+
+        setHrefAttribute(newAttrs, rewrittenURL);
+    }
+
+    /**
+     * Sets the value of the href attribute.
+     * 
+     * @param attr The attributes.
+     * @param value The value.
+     * @throws IllegalArgumentException if the href attribute is not contained in this attributes.
+     */
+    protected void setHrefAttribute(AttributesImpl attr, String value) {
+        int position = attr.getIndex(ATTRIBUTE_HREF);
+        if (position == -1) {
+            throw new IllegalArgumentException("The href attribute is not available!");
+        }
+        attr.setValue(position, value);
+    }
+
+    /**
+     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
+     *      java.lang.String)
+     */
+    public void endElement(String uri, String name, String qname) throws SAXException {
+        if (getLogger().isDebugEnabled()) {
+            this.indent = this.indent.substring(2);
+            getLogger().debug(this.indent + "</" + qname + ">");
+        }
+        if (lookingAtAElement(name) && this.ignoreAElement) {
+            this.ignoreAElement = false;
+        } else {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug(this.indent + "</" + qname + "> sent");
+            }
+            super.endElement(uri, name, qname);
+        }
+    }
+
+    private boolean lookingAtAElement(String name) {
+        return name.equals("a");
+    }
+
+    /**
+     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     */
+    public void dispose() {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Disposing transformer");
+        }
+        if (this.serviceSelector != null) {
+            if (this.acResolver != null) {
+                this.serviceSelector.release(this.acResolver);
+            }
+            this.manager.release(this.serviceSelector);
+        }
+        if (this.linkResolver != null) {
+            this.manager.release(this.linkResolver);
+        }
+    }
+
+    /**
+     * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
+     */
+    public void recycle() {
+        this.ignoreAElement = false;
+    }
+}
\ No newline at end of file

Added: lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolver.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolver.java?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolver.java (added)
+++ lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolver.java Thu Nov  9 09:16:14 2006
@@ -0,0 +1,39 @@
+/*
+ * Copyright  1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.lenya.cms.linking;
+
+import java.net.MalformedURLException;
+
+import org.apache.lenya.cms.publication.Document;
+
+/**
+ * Resolve a link from a document to another document.
+ */
+public interface LinkResolver {
+    
+    String ROLE = LinkResolver.class.getName();
+    
+    /**
+     * Resolve a link.
+     * @param currentDocument The document which contains the link.
+     * @param linkUri The link URI.
+     * @return A document or <code>null</code> if the target document does not exist.
+     * @throws MalformedURLException if the URI is invalid.
+     */
+    Document resolve(Document currentDocument, String linkUri) throws MalformedURLException;
+
+}

Added: lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolverImpl.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolverImpl.java?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolverImpl.java (added)
+++ lenya/trunk/src/modules-core/linking/java/src/org/apache/lenya/cms/linking/LinkResolverImpl.java Thu Nov  9 09:16:14 2006
@@ -0,0 +1,71 @@
+/*
+ * Copyright  1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.lenya.cms.linking;
+
+import java.net.MalformedURLException;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.Publication;
+import org.apache.lenya.cms.publication.PublicationException;
+import org.apache.lenya.util.Query;
+
+public class LinkResolverImpl extends AbstractLogEnabled implements LinkResolver {
+
+    public static final String ROLE = LinkResolverImpl.class.getName();
+    protected static final String PAIR_DELIMITER = ",";
+    protected static final String KEY_VALUE_DELIMITER = "=";
+
+    public Document resolve(Document currentDoc, String linkUri) throws MalformedURLException {
+
+        String[] schemeAndPath = linkUri.split(":");
+        String path = schemeAndPath[1];
+
+        String pubId;
+        String uuid;
+        String area;
+        String language;
+
+        if (path.indexOf(PAIR_DELIMITER) > -1) {
+            int firstDelimiterIndex = path.indexOf(PAIR_DELIMITER);
+            uuid = path.substring(0, firstDelimiterIndex);
+            String pathQueryString = path.substring(firstDelimiterIndex + 1);
+            Query query = new Query(pathQueryString, PAIR_DELIMITER, KEY_VALUE_DELIMITER);
+            pubId = query.getValue("pub", currentDoc.getPublication().getId());
+            area = query.getValue("area", currentDoc.getArea());
+            language = query.getValue("lang", currentDoc.getLanguage());
+        } else {
+            uuid = path;
+            pubId = currentDoc.getPublication().getId();
+            area = currentDoc.getArea();
+            language = currentDoc.getLanguage();
+        }
+
+        if (uuid.length() == 0) {
+            uuid = currentDoc.getUUID();
+        }
+
+        try {
+            Publication pub = currentDoc.getFactory().getPublication(pubId);
+            Document doc = pub.getArea(area).getDocument(uuid, language);
+            return doc;
+        } catch (PublicationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

Added: lenya/trunk/src/modules-core/linking/module.xml
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/linking/module.xml?view=auto&rev=472981
==============================================================================
--- lenya/trunk/src/modules-core/linking/module.xml (added)
+++ lenya/trunk/src/modules-core/linking/module.xml Thu Nov  9 09:16:14 2006
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 1999-2005 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<!-- $Id: publication.xml 374687 2006-02-03 15:24:55Z michi $ -->
+
+<module xmlns="http://apache.org/lenya/module/1.0">
+  <id>org.apache.lenya.modules.linking</id>
+  <published>false</published>
+  <package>org.apache.lenya.modules</package>
+  <version>0.1-dev</version>
+  <name>Linking</name>
+  <lenya-version>@lenya.version@</lenya-version>
+  <description>Components to handle internal links.</description>
+</module>

Modified: lenya/trunk/src/modules/bxe/resources/javascript/insertLink.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/bxe/resources/javascript/insertLink.js?view=diff&rev=472981&r1=472980&r2=472981
==============================================================================
--- lenya/trunk/src/modules/bxe/resources/javascript/insertLink.js (original)
+++ lenya/trunk/src/modules/bxe/resources/javascript/insertLink.js Thu Nov  9 09:16:14 2006
@@ -12,9 +12,9 @@
     window.close();
 }
 
-function setLink(src) { 
-    url = src;
-    document.forms["link"].url.value = url;
+function setLink(uuid) {
+    var language = CHOSEN_LANGUAGE;
+    document.forms["link"].url.value = "lenya-document:" + uuid + ",lang=" + language;
 }
 
 function insertText() { 
@@ -34,7 +34,7 @@
 LinkTree.prototype = new NavTree;
 
 LinkTree.prototype.handleItemClick = function(item, event) {
-    setLink(item.href);
+    setLink(item.uuid);
 }
 
 function buildTree() {

Modified: lenya/trunk/src/modules/bxe/xslt/link.xsl
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/bxe/xslt/link.xsl?view=diff&rev=472981&r1=472980&r2=472981
==============================================================================
--- lenya/trunk/src/modules/bxe/xslt/link.xsl (original)
+++ lenya/trunk/src/modules/bxe/xslt/link.xsl Thu Nov  9 09:16:14 2006
@@ -95,19 +95,15 @@
                     <td colspan="2">&#160;</td>
                   </tr>
                   <tr>
-                    <td class="lenya-form-caption">URL:</td>
+                    <td class="lenya-form-caption"><i18n:text>URL</i18n:text>:</td>
                     <td>
-                      <input class="lenya-form-element" 
-                        type="text" 
-                        name="url"/>
+                      <input class="lenya-form-element" type="text" name="url"/>
                     </td>
                   </tr>
                   <tr>
-                    <td class="lenya-form-caption">Title:</td>
+                    <td class="lenya-form-caption"><i18n:text>Title</i18n:text>:</td>
                     <td>
-                      <input class="lenya-form-element" 
-                        type="text" 
-                        name="title"/>
+                      <input class="lenya-form-element" type="text" name="title"/>
                     </td>
                   </tr>
                   <tr>

Modified: lenya/trunk/src/modules/sitetree/resources/javascript/navtree.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/sitetree/resources/javascript/navtree.js?view=diff&rev=472981&r1=472980&r2=472981
==============================================================================
--- lenya/trunk/src/modules/sitetree/resources/javascript/navtree.js (original)
+++ lenya/trunk/src/modules/sitetree/resources/javascript/navtree.js Thu Nov  9 09:16:14 2006
@@ -23,6 +23,7 @@
     this.parent = parent;
     this.items = {};
     this.isfolder = false;
+    this.uuid = '';
     this.href = '';
     this.label = '';
     this.area = '';
@@ -42,6 +43,7 @@
     newItem.isfolder = isNodeFolder(node);
     newItem.area = this.area;
     newItem.path = node.getAttribute('basic-url');
+    newItem.uuid = node.getAttribute('uuid');
     newItem.isprotected = isNodeProtected(node);
     newItem.href = node.getAttribute('href');
     newItem.label = getLabel(node);

Modified: lenya/trunk/src/modules/xhtml/sitemap.xmap
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/xhtml/sitemap.xmap?view=diff&rev=472981&r1=472980&r2=472981
==============================================================================
--- lenya/trunk/src/modules/xhtml/sitemap.xmap (original)
+++ lenya/trunk/src/modules/xhtml/sitemap.xmap Thu Nov  9 09:16:14 2006
@@ -92,7 +92,7 @@
       <!-- parametrized doctype matcher -->
       <!-- pattern="{rendertype}" -->
       <map:match pattern="*.xml">
-        <map:generate src="lenyadoc:/{page-envelope:document-language}/{page-envelope:document-id}"/>
+        <map:generate src="lenya-document:{page-envelope:document-uuid},lang={page-envelope:document-language}"/>
         <map:transform src="fallback://lenya/modules/xhtml/xslt/xhtml2xhtml.xsl">
           <map:parameter name="rendertype" value="{request-param:rendertype}"/>
           <map:parameter name="nodeid" value="{page-envelope:document-name}"/>



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org