KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > staticexport > CmsLinkManager


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/staticexport/CmsLinkManager.java,v $
3  * Date : $Date: 2006/10/18 09:29:06 $
4  * Version: $Revision: 1.62 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.staticexport;
33
34 import org.opencms.file.CmsObject;
35 import org.opencms.file.types.CmsResourceTypeImage;
36 import org.opencms.main.CmsException;
37 import org.opencms.main.CmsLog;
38 import org.opencms.main.OpenCms;
39 import org.opencms.site.CmsSite;
40 import org.opencms.site.CmsSiteManager;
41 import org.opencms.site.CmsSiteMatcher;
42 import org.opencms.util.CmsStringUtil;
43 import org.opencms.validation.CmsPointerLinkValidationResult;
44 import org.opencms.workplace.CmsWorkplace;
45
46 import java.net.MalformedURLException JavaDoc;
47 import java.net.URI JavaDoc;
48 import java.net.URL JavaDoc;
49
50 import org.apache.commons.logging.Log;
51
52 /**
53  * Does the link replacement for the &lg;link&gt; tags.<p>
54  *
55  * Since this functionality is closely related to the static export,
56  * this class resides in the static export package.<p>
57  *
58  * @author Alexander Kandzior
59  *
60  * @version $Revision: 1.62 $
61  *
62  * @since 6.0.0
63  */

64 public class CmsLinkManager {
65
66     /** The log object for this class. */
67     private static final Log LOG = CmsLog.getLog(CmsLinkManager.class);
68
69     /** Base URL to calculate absolute links. */
70     private static URL JavaDoc m_baseUrl;
71
72     /** Stores the results of a extern link validation. */
73     private CmsPointerLinkValidationResult m_pointerLinkValidationResult;
74
75     /**
76      * Public constructor.<p>
77      */

78     public CmsLinkManager() {
79
80         // empty
81
}
82
83     /**
84      * Static initializer for the base URL.<p>
85      */

86     static {
87         m_baseUrl = null;
88         try {
89             m_baseUrl = new URL JavaDoc("http://127.0.0.1");
90         } catch (MalformedURLException JavaDoc e) {
91             // this won't happen
92
}
93     }
94
95     /**
96      * Calculates the absolute uri for the "relativeUri" with the given absolute "baseUri" as start. <p>
97      *
98      * If "relativeUri" is already absolute, it is returned unchanged.
99      * This method also returns "relativeUri" unchanged if it is not well-formed.<p>
100      *
101      * @param relativeUri the relative uri to calculate an absolute uri for
102      * @param baseUri the base uri, this must be an absolute uri
103      * @return an absolute uri calculated from "relativeUri" and "baseUri"
104      */

105     public static String JavaDoc getAbsoluteUri(String JavaDoc relativeUri, String JavaDoc baseUri) {
106
107         if ((relativeUri == null) || (relativeUri.length() >= 1 && relativeUri.charAt(0) == '/')) {
108             // uri is null or already absolute
109
return relativeUri;
110         }
111         try {
112             URL JavaDoc url = new URL JavaDoc(new URL JavaDoc(m_baseUrl, baseUri), relativeUri);
113             if (url.getQuery() == null) {
114                 return url.getPath();
115             } else {
116                 StringBuffer JavaDoc result = new StringBuffer JavaDoc(url.getPath().length() + url.getQuery().length() + 2);
117                 result.append(url.getPath());
118                 result.append('?');
119                 result.append(url.getQuery());
120                 return result.toString();
121             }
122         } catch (MalformedURLException JavaDoc e) {
123             return relativeUri;
124         }
125     }
126
127     /**
128      * Calculates a realtive uri from "fromUri" to "toUri",
129      * both uri's must be absolute.<p>
130      *
131      * @param fromUri the uri to start
132      * @param toUri the uri to calculate a relative path to
133      * @return a realtive uri from "fromUri" to "toUri"
134      */

135     public static String JavaDoc getRelativeUri(String JavaDoc fromUri, String JavaDoc toUri) {
136
137         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
138         int pos = 0;
139
140         while (true) {
141             int i = fromUri.indexOf('/', pos);
142             int j = toUri.indexOf('/', pos);
143             if ((i == -1) || (i != j) || !fromUri.regionMatches(pos, toUri, pos, i - pos)) {
144                 break;
145             }
146             pos = i + 1;
147         }
148
149         // count hops up from here to the common ancestor
150
for (int i = fromUri.indexOf('/', pos); i > 0; i = fromUri.indexOf('/', i + 1)) {
151             result.append("../");
152         }
153
154         // append path down from common ancestor to there
155
result.append(toUri.substring(pos));
156
157         if (result.length() == 0) {
158             // special case: relative link to the parent folder from a file in that folder
159
result.append("./");
160         }
161
162         return result.toString();
163     }
164
165     /**
166      * Returns the site path for a given uri.<p>
167      *
168      * If the uri contains no site information, but starts with the opencms context, the context is removed.<p>
169      * <code>/opencms/opencms/system/further_path -> /system/further_path</code>
170      *
171      * If the uri contains no site information, the path will be prefixed with the current site
172      * (if mysite is the site currently selected in the workplace or in the request).<p>
173      * <pre>
174      * /folder/page.html -> /sites/mysite/folder/page.html
175      * </pre>
176      *
177      * If the path of the uri is relative, i.e. does not start with "/",
178      * the path will be prefixed with the current site and the given relative path,
179      * then normalized.
180      * If no relative path is given, null is returned.
181      * If the normalized path is outsite a site, null is returned.<p>
182      * <pre>
183      * page.html -> /sites/mysite/{relativePath}/page.html
184      * ../page.html -> /sites/mysite/page.html
185      * ../../page.html -> null
186      * </pre>
187      *
188      * If the uri contains a scheme/server name that denotes an opencms site,
189      * it is replaced by the appropriate site path.<p>
190      * <pre>
191      * http://www.mysite.de/folder/page.html -> /sites/mysite/folder/page.html
192      * </pre>
193      *
194      * If the uri contains a scheme/server name that does not match with any site,
195      * or if the uri is opaque or invalid,
196      * null is returned.<p>
197      * <pre>
198      * http://www.elsewhere.com/page.html -> null
199      * mailto:someone@elsewhere.com -> null
200      * </pre>
201      *
202      * @param cms the cms object
203      * @param relativePath path to use as prefix if neccessary
204      * @param targetUri the target uri
205      * @return the root path for the target uri or null
206      */

207     public static String JavaDoc getSitePath(CmsObject cms, String JavaDoc relativePath, String JavaDoc targetUri) {
208
209         if (cms == null) {
210             // required by unit test cases
211
return targetUri;
212         }
213
214         URI JavaDoc uri;
215         String JavaDoc path;
216         String JavaDoc fragment;
217         String JavaDoc query;
218         String JavaDoc suffix;
219
220         // malformed uri
221
try {
222
223             uri = new URI JavaDoc(targetUri);
224             path = uri.getPath();
225
226             fragment = uri.getFragment();
227             if (fragment != null) {
228                 fragment = "#" + fragment;
229             } else {
230                 fragment = "";
231             }
232
233             query = uri.getQuery();
234             if (query != null) {
235                 query = "?" + query;
236             } else {
237                 query = "";
238             }
239
240         } catch (Exception JavaDoc e) {
241             if (LOG.isWarnEnabled()) {
242                 LOG.warn(Messages.get().getBundle().key(Messages.LOG_MALFORMED_URI_1, targetUri), e);
243             }
244             return null;
245         }
246
247         // concat fragment and query
248
suffix = fragment.concat(query);
249
250         // opaque URI
251
if (uri.isOpaque()) {
252             return null;
253         }
254
255         // absolute URI (i.e. uri has a scheme component like http:// ...)
256
if (uri.isAbsolute()) {
257             CmsSiteMatcher matcher = new CmsSiteMatcher(targetUri);
258             if (OpenCms.getSiteManager().isMatching(matcher)) {
259                 if (path.startsWith(OpenCms.getSystemInfo().getOpenCmsContext())) {
260                     path = path.substring(OpenCms.getSystemInfo().getOpenCmsContext().length());
261                 }
262
263                 return cms.getRequestContext().addSiteRoot(
264                     OpenCms.getSiteManager().matchSite(matcher).getSiteRoot(),
265                     path + suffix);
266             } else {
267                 return null;
268             }
269         }
270
271         // relative URI (i.e. no scheme component, but filename can still start with "/")
272
String JavaDoc context = OpenCms.getSystemInfo().getOpenCmsContext();
273         if ((context != null) && path.startsWith(context)) {
274             // URI is starting with opencms context
275

276             String JavaDoc siteRoot = null;
277             if (relativePath != null) {
278                 siteRoot = CmsSiteManager.getSiteRoot(relativePath);
279             }
280
281             // cut context from path
282
path = path.substring(context.length());
283
284             if (siteRoot != null) {
285                 // special case: relative path contains a site root, i.e. we are in the root site
286
if (!path.startsWith(siteRoot)) {
287                     // path does not already start with the site root, we have to add this path as site prefix
288
return cms.getRequestContext().addSiteRoot(siteRoot, path + suffix);
289                 } else {
290                     // since path already contains the site root, we just leave it unchanged
291
return path + suffix;
292                 }
293             } else {
294                 // site root is added with standard mechanism
295
return cms.getRequestContext().addSiteRoot(path + suffix);
296             }
297         }
298
299         // URI with relative path is relative to the given relativePath if available and in a site,
300
// otherwise invalid
301
if (CmsStringUtil.isNotEmpty(path) && (path.charAt(0) != '/')) {
302             if (relativePath != null) {
303                 String JavaDoc absolutePath;
304                 int pos = path.indexOf("../../galleries/pics/");
305                 if (pos >= 0) {
306                     // HACK: mixed up editor path to system gallery image folder
307
return CmsWorkplace.VFS_PATH_SYSTEM + path.substring(pos + 6) + suffix;
308                 }
309                 absolutePath = getAbsoluteUri(path, cms.getRequestContext().addSiteRoot(relativePath));
310                 if (CmsSiteManager.getSiteRoot(absolutePath) != null) {
311                     return absolutePath + suffix;
312                 }
313                 // HACK: some editor components (e.g. HtmlArea) mix up the editor URL with the current request URL
314
absolutePath = getAbsoluteUri(path, cms.getRequestContext().getSiteRoot()
315                     + CmsWorkplace.VFS_PATH_EDITORS);
316                 if (CmsSiteManager.getSiteRoot(absolutePath) != null) {
317                     return absolutePath + suffix;
318                 }
319                 // HACK: same as above, but XmlContent editor has one path element more
320
absolutePath = getAbsoluteUri(path, cms.getRequestContext().getSiteRoot()
321                     + CmsWorkplace.VFS_PATH_EDITORS
322                     + "xmlcontent/");
323                 if (CmsSiteManager.getSiteRoot(absolutePath) != null) {
324                     return absolutePath + suffix;
325                 }
326             }
327
328             return null;
329         }
330
331         // relative uri (= vfs path relative to currently selected site root)
332
if (CmsStringUtil.isNotEmpty(path)) {
333             return cms.getRequestContext().addSiteRoot(path) + suffix;
334         }
335
336         // uri without path (typically local link)
337
return suffix;
338     }
339
340     /**
341      * Returns the result of the last extern link validation.<p>
342      *
343      * @return the result of the last extern link validation
344      */

345     public CmsPointerLinkValidationResult getPointerLinkValidationResult() {
346
347         return m_pointerLinkValidationResult;
348     }
349
350     /**
351      * Sets the result of a extern link validation.<p>
352      *
353      * @param externLinkValidationResult the result a extern link validation
354      */

355     public void setPointerLinkValidationResult(CmsPointerLinkValidationResult externLinkValidationResult) {
356
357         m_pointerLinkValidationResult = externLinkValidationResult;
358     }
359
360     /**
361      * Substitutes the contents of a link by adding the context path and
362      * servlet name, and in the case of the "online" project also according
363      * to the configured static export settings.<p>
364      *
365      * @param cms the cms context
366      * @param link the link to process (must be a valid link to a VFS resource with optional parameters)
367      * @return the substituted link
368      */

369     public String JavaDoc substituteLink(CmsObject cms, String JavaDoc link) {
370
371         return substituteLink(cms, link, null);
372     }
373
374     /**
375      * Substitutes the contents of a link by adding the context path and
376      * servlet name, and in the case of the "online" project also according
377      * to the configured static export settings.<p>
378      *
379      * A server prefix is prepended if
380      * <ul>
381      * <li>the link points to another site</li>
382      * <li>the link is contained in a normal document and the link references a secure document</li>
383      * <li>the link is contained in a secure document and the link references a normal document</li>
384      * </ul>
385      *
386      * @param cms the cms context
387      * @param link the link to process (must be a valid link to a VFS resource with optional parameters)
388      * @param siteRoot the site root of the link
389      *
390      * @return the substituted link
391      */

392     public String JavaDoc substituteLink(CmsObject cms, String JavaDoc link, String JavaDoc siteRoot) {
393
394         return substituteLink(cms, link, siteRoot, false);
395     }
396
397     /**
398      * Substitutes the contents of a link by adding the context path and
399      * servlet name, and in the case of the "online" project also according
400      * to the configured static export settings.<p>
401      *
402      * A server prefix is prepended if
403      * <ul>
404      * <li>the link points to another site</li>
405      * <li>the link is contained in a normal document and the link references a secure document</li>
406      * <li>the link is contained in a secure document and the link references a normal document</li>
407      * </ul>
408      *
409      * @param cms the cms context
410      * @param link the link to process (must be a valid link to a VFS resource with optional parameters)
411      * @param siteRoot the site root of the link
412      * @param forceSecure if <code>true</code> generates always an absolute url (with protocoll and server name) for secure links
413      *
414      * @return the substituted link
415      */

416     public String JavaDoc substituteLink(CmsObject cms, String JavaDoc link, String JavaDoc siteRoot, boolean forceSecure) {
417
418         if (CmsStringUtil.isEmpty(link)) {
419             // not a valid link parameter, return an empty String
420
return "";
421         }
422         // make sure we have an absolute link
423
String JavaDoc absoluteLink = CmsLinkManager.getAbsoluteUri(link, cms.getRequestContext().getUri());
424
425         String JavaDoc vfsName;
426         String JavaDoc parameters;
427         int pos = absoluteLink.indexOf('?');
428         // check if the link has parameters, if so cut them
429
if (pos >= 0) {
430             vfsName = absoluteLink.substring(0, pos);
431             parameters = absoluteLink.substring(pos);
432         } else {
433             vfsName = absoluteLink;
434             parameters = null;
435         }
436
437         String JavaDoc resultLink = null;
438         String JavaDoc uriBaseName = null;
439         boolean useRelativeLinks = false;
440
441         // determine the target site of the link
442
CmsSite targetSite;
443         if (CmsStringUtil.isNotEmpty(siteRoot)) {
444             targetSite = CmsSiteManager.getSite(siteRoot);
445         } else {
446             targetSite = CmsSiteManager.getCurrentSite(cms);
447         }
448         String JavaDoc serverPrefix = "";
449         // if the link points to another site, there needs to be a server prefix
450
if (targetSite != CmsSiteManager.getCurrentSite(cms)) {
451             serverPrefix = targetSite.getUrl();
452         }
453
454         if (cms.getRequestContext().currentProject().isOnlineProject()) {
455
456             CmsStaticExportManager exportManager = OpenCms.getStaticExportManager();
457             // check if we need relative links in the exported pages
458
if (exportManager.relativeLinksInExport(cms.getRequestContext().getSiteRoot()
459                 + cms.getRequestContext().getUri())) {
460                 // try to get base uri from cache
461
uriBaseName = exportManager.getCachedOnlineLink(exportManager.getCacheKey(
462                     cms.getRequestContext().getSiteRoot(),
463                     cms.getRequestContext().getUri()));
464                 if (uriBaseName == null) {
465                     // base not cached, check if we must export it
466
if (exportManager.isExportLink(cms, cms.getRequestContext().getUri())) {
467                         // base uri must also be exported
468
uriBaseName = exportManager.getRfsName(cms,
469                         //cms.getRequestContext().getSiteRoot(),
470
cms.getRequestContext().getUri());
471                     } else {
472                         // base uri dosn't need to be exported
473
uriBaseName = exportManager.getVfsPrefix() + cms.getRequestContext().getUri();
474                     }
475                     // cache export base uri
476
exportManager.cacheOnlineLink(exportManager.getCacheKey(
477                         cms.getRequestContext().getSiteRoot(),
478                         cms.getRequestContext().getUri()), uriBaseName);
479                 }
480                 // use relative links only on pages that get exported
481
useRelativeLinks = uriBaseName.startsWith(OpenCms.getStaticExportManager().getRfsPrefix(
482                     cms.getRequestContext().getSiteRoot() + cms.getRequestContext().getUri()));
483             }
484
485             // check if we have the absolute vfs name for the link target cached
486
resultLink = exportManager.getCachedOnlineLink(cms.getRequestContext().getSiteRoot() + ":" + absoluteLink);
487             if (resultLink == null) {
488                 cms.getRequestContext().saveSiteRoot();
489                 cms.getRequestContext().setSiteRoot(targetSite.getSiteRoot());
490                 // didn't find the link in the cache
491
if (exportManager.isExportLink(cms, vfsName)) {
492                     // export required, get export name for target link
493
resultLink = exportManager.getRfsName(cms, vfsName, parameters);
494                     // now set the parameters to null, we do not need them anymore
495
parameters = null;
496                 } else {
497                     // no export required for the target link
498
resultLink = exportManager.getVfsPrefix().concat(vfsName);
499                     // add cut off parameters if required
500
if (parameters != null) {
501                         resultLink = resultLink.concat(parameters);
502                     }
503                 }
504                 cms.getRequestContext().restoreSiteRoot();
505                 // cache the result
506
exportManager.cacheOnlineLink(cms.getRequestContext().getSiteRoot() + ":" + absoluteLink, resultLink);
507             }
508
509             // read only properties, if the current site and the target site both do have a secure server
510
if (targetSite.hasSecureServer() || CmsSiteManager.getCurrentSite(cms).hasSecureServer()) {
511                 if (!vfsName.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) {
512
513                     int linkType = -1;
514                     try {
515                         // read the linked resource
516
linkType = cms.readResource(vfsName).getTypeId();
517                     } catch (CmsException e) {
518                         // the resource could not be read
519
if (LOG.isInfoEnabled()) {
520                             String JavaDoc message = Messages.get().getBundle().key(
521                                 Messages.LOG_RESOURCE_ACESS_ERROR_3,
522                                 vfsName,
523                                 cms.getRequestContext().currentUser().getName(),
524                                 cms.getRequestContext().getSiteRoot());
525                             if (LOG.isDebugEnabled()) {
526                                 LOG.debug(message, e);
527                             } else {
528                                 LOG.info(message);
529                             }
530                         }
531                     }
532
533                     // images are always referenced without a server prefix
534
if (linkType != CmsResourceTypeImage.getStaticTypeId()) {
535                         // check the secure property of the link
536
boolean secureLink = exportManager.isSecureLink(cms, vfsName, targetSite.getSiteRoot());
537                         boolean secureRequest = exportManager.isSecureLink(cms, cms.getRequestContext().getUri());
538                         // if we are on a normal server, and the requested resource is secure,
539
// the server name has to be prepended
540
if (secureLink && (forceSecure || !secureRequest)) {
541                             serverPrefix = targetSite.getSecureUrl();
542                         } else if (!secureLink && secureRequest) {
543                             serverPrefix = targetSite.getUrl();
544                         }
545                     }
546                 }
547             }
548             // make absolute link relative, if relative links in export are required
549
// and if the link does not point to another server
550
if (useRelativeLinks && CmsStringUtil.isEmpty(serverPrefix)) {
551                 resultLink = getRelativeUri(uriBaseName, resultLink);
552             }
553
554         } else {
555
556             // offline project, no export required
557
if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) {
558                 // in unit test this code would fail otherwise
559
resultLink = OpenCms.getStaticExportManager().getVfsPrefix().concat(vfsName);
560             }
561
562             // add cut off parameters and return the result
563
if (parameters != null) {
564                 resultLink = resultLink.concat(parameters);
565             }
566
567         }
568         return serverPrefix.concat(resultLink);
569     }
570
571 }
Popular Tags