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 java.util.HashSet;
021: import java.util.Set;
022:
023: import org.apache.avalon.framework.logger.AbstractLogEnabled;
024: import org.apache.avalon.framework.service.ServiceException;
025: import org.apache.avalon.framework.service.ServiceManager;
026: import org.apache.avalon.framework.service.Serviceable;
027: import org.apache.lenya.cms.publication.Document;
028: import org.apache.lenya.xml.DocumentHelper;
029: import org.apache.xpath.XPathAPI;
030: import org.w3c.dom.Attr;
031: import org.w3c.dom.Node;
032: import org.w3c.dom.traversal.NodeIterator;
033:
034: /**
035: * Basic link manager implementation which searches for links by parsing the
036: * document content. For better performance use an implementation which is based
037: * on meta data or a centralized link registry.
038: */
039: public class ContentLinkManager extends AbstractLogEnabled implements
040: LinkManager, Serviceable {
041:
042: protected ServiceManager manager;
043:
044: public Link[] getLinksFrom(Document source) {
045:
046: Set links = new HashSet();
047:
048: try {
049: String[] xPaths = source.getResourceType()
050: .getLinkAttributeXPaths();
051: if (xPaths.length > 0) {
052: org.w3c.dom.Document xml = DocumentHelper
053: .readDocument(source.getInputStream());
054:
055: if (xml == null) {
056: throw new RuntimeException("The document ["
057: + source
058: + "] doesn't contain any XML content.");
059: }
060:
061: for (int i = 0; i < xPaths.length; i++) {
062: NodeIterator iter = XPathAPI.selectNodeIterator(
063: xml, xPaths[i]);
064: Node node;
065: while ((node = iter.nextNode()) != null) {
066: Attr attr = (Attr) node;
067: String uri = attr.getValue();
068: if (isLinkUri(uri)) {
069: links.add(new Link(uri));
070: }
071: }
072: }
073: }
074: } catch (RuntimeException e) {
075: throw e;
076: } catch (Exception e) {
077: throw new RuntimeException(e);
078: }
079:
080: return (Link[]) links.toArray(new Link[links.size()]);
081: }
082:
083: protected boolean isLinkUri(String uri) {
084: return uri.startsWith(LinkResolver.SCHEME + ":");
085: }
086:
087: public Document[] getReferencingDocuments(Document target) {
088:
089: Document[] allDocs = target.area().getDocuments();
090: Set docs = new HashSet();
091:
092: LinkResolver resolver = null;
093: try {
094: resolver = (LinkResolver) this .manager
095: .lookup(LinkResolver.ROLE);
096: for (int d = 0; d < allDocs.length; d++) {
097:
098: Link[] links = getLinksFrom(allDocs[d]);
099: for (int l = 0; l < links.length; l++) {
100: LinkTarget linkTarget = resolver.resolve(
101: allDocs[d], links[l].getUri());
102: if (linkTarget.exists()
103: && linkTarget.getDocument().equals(target)) {
104: docs.add(allDocs[d]);
105: }
106: }
107: }
108: } catch (Exception e) {
109: throw new RuntimeException(e);
110: } finally {
111: if (resolver != null) {
112: this .manager.release(resolver);
113: }
114: }
115: return (Document[]) docs.toArray(new Document[docs.size()]);
116: }
117:
118: public void service(ServiceManager manager) throws ServiceException {
119: this.manager = manager;
120: }
121:
122: }
|