Source Code Cross Referenced for CmsStaticExportManager.java in  » Content-Management-System » opencms » org » opencms » staticexport » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » opencms » org.opencms.staticexport 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * File   : $Source: /usr/local/cvs/opencms/src/org/opencms/staticexport/CmsStaticExportManager.java,v $
0003:         * Date   : $Date: 2008-02-27 12:05:46 $
0004:         * Version: $Revision: 1.132 $
0005:         *
0006:         * This library is part of OpenCms -
0007:         * the Open Source Content Management System
0008:         *
0009:         * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
0010:         *
0011:         * This library is free software; you can redistribute it and/or
0012:         * modify it under the terms of the GNU Lesser General Public
0013:         * License as published by the Free Software Foundation; either
0014:         * version 2.1 of the License, or (at your option) any later version.
0015:         *
0016:         * This library is distributed in the hope that it will be useful,
0017:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0019:         * Lesser General Public License for more details.
0020:         *
0021:         * For further information about Alkacon Software GmbH, please see the
0022:         * company website: http://www.alkacon.com
0023:         *
0024:         * For further information about OpenCms, please see the
0025:         * project website: http://www.opencms.org
0026:         * 
0027:         * You should have received a copy of the GNU Lesser General Public
0028:         * License along with this library; if not, write to the Free Software
0029:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0030:         */
0031:
0032:        package org.opencms.staticexport;
0033:
0034:        import org.opencms.file.CmsFile;
0035:        import org.opencms.file.CmsObject;
0036:        import org.opencms.file.CmsProperty;
0037:        import org.opencms.file.CmsPropertyDefinition;
0038:        import org.opencms.file.CmsResource;
0039:        import org.opencms.file.CmsVfsResourceNotFoundException;
0040:        import org.opencms.file.types.CmsResourceTypeJsp;
0041:        import org.opencms.i18n.CmsAcceptLanguageHeaderParser;
0042:        import org.opencms.i18n.CmsI18nInfo;
0043:        import org.opencms.i18n.CmsLocaleManager;
0044:        import org.opencms.loader.I_CmsResourceLoader;
0045:        import org.opencms.main.CmsContextInfo;
0046:        import org.opencms.main.CmsEvent;
0047:        import org.opencms.main.CmsException;
0048:        import org.opencms.main.CmsIllegalArgumentException;
0049:        import org.opencms.main.CmsLog;
0050:        import org.opencms.main.CmsSystemInfo;
0051:        import org.opencms.main.I_CmsEventListener;
0052:        import org.opencms.main.OpenCms;
0053:        import org.opencms.report.CmsLogReport;
0054:        import org.opencms.report.I_CmsReport;
0055:        import org.opencms.security.CmsSecurityException;
0056:        import org.opencms.util.CmsFileUtil;
0057:        import org.opencms.util.CmsMacroResolver;
0058:        import org.opencms.util.CmsRequestUtil;
0059:        import org.opencms.util.CmsStringUtil;
0060:        import org.opencms.util.CmsUUID;
0061:        import org.opencms.workplace.CmsWorkplace;
0062:
0063:        import java.io.File;
0064:        import java.io.FileFilter;
0065:        import java.io.FileOutputStream;
0066:        import java.io.IOException;
0067:        import java.net.MalformedURLException;
0068:        import java.net.URL;
0069:        import java.util.ArrayList;
0070:        import java.util.Collections;
0071:        import java.util.HashMap;
0072:        import java.util.Iterator;
0073:        import java.util.List;
0074:        import java.util.Locale;
0075:        import java.util.Map;
0076:
0077:        import javax.servlet.ServletException;
0078:        import javax.servlet.http.HttpServletRequest;
0079:        import javax.servlet.http.HttpServletResponse;
0080:
0081:        import org.apache.commons.collections.map.LRUMap;
0082:        import org.apache.commons.logging.Log;
0083:
0084:        /**
0085:         * Provides the functionality to export resources from the OpenCms VFS
0086:         * to the file system.<p>
0087:         *
0088:         * @author Alexander Kandzior 
0089:         * @author Michael Moossen 
0090:         * 
0091:         * @version $Revision: 1.132 $ 
0092:         * 
0093:         * @since 6.0.0 
0094:         */
0095:        public class CmsStaticExportManager implements  I_CmsEventListener {
0096:
0097:            /**
0098:             * Implements the file filter used to guess the right suffix of a deleted jsp file.<p>
0099:             */
0100:            private static class CmsPrefixFileFilter implements  FileFilter {
0101:
0102:                /** The base file. */
0103:                private String m_baseName;
0104:
0105:                /**
0106:                 * Creates a new instance of this filter.<p>
0107:                 * 
0108:                 * @param fileName the base file to compare with.
0109:                 */
0110:                public CmsPrefixFileFilter(String fileName) {
0111:
0112:                    m_baseName = fileName + ".";
0113:                }
0114:
0115:                /**
0116:                 * Accepts the given file if its name starts with the name of of the base file (without extension) 
0117:                 * and ends with the extension.<p>
0118:                 * 
0119:                 * @see java.io.FileFilter#accept(java.io.File)
0120:                 */
0121:                public boolean accept(File f) {
0122:
0123:                    return f.getName().startsWith(m_baseName)
0124:                            && (f.getName().length() > m_baseName.length())
0125:                            && (f.getName().indexOf('.', m_baseName.length()) < 0);
0126:                }
0127:            }
0128:
0129:            /** Marker for error message attribute. */
0130:            public static final String EXPORT_ATTRIBUTE_ERROR_MESSAGE = "javax.servlet.error.message";
0131:
0132:            /** Marker for error request uri attribute. */
0133:            public static final String EXPORT_ATTRIBUTE_ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
0134:
0135:            /** Marker for error servlet name attribute. */
0136:            public static final String EXPORT_ATTRIBUTE_ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
0137:
0138:            /** Marker for error status code attribute. */
0139:            public static final String EXPORT_ATTRIBUTE_ERROR_STATUS_CODE = "javax.servlet.error.status_code";
0140:
0141:            /** Name for the backup folder default name. */
0142:            public static final String EXPORT_BACKUP_FOLDER_NAME = "backup";
0143:
0144:            /** Name for the default work path. */
0145:            public static final Integer EXPORT_DEFAULT_BACKUPS = new Integer(0);
0146:
0147:            /** Name for the folder default index file. */
0148:            public static final String EXPORT_DEFAULT_FILE = "index_export.html";
0149:
0150:            /** Name for the default work path. */
0151:            public static final String EXPORT_DEFAULT_WORKPATH = CmsSystemInfo.FOLDER_WEBINF
0152:                    + "temp";
0153:
0154:            /** Flag value for links without parameters. */
0155:            public static final int EXPORT_LINK_WITH_PARAMETER = 2;
0156:
0157:            /** Flag value for links without parameters. */
0158:            public static final int EXPORT_LINK_WITHOUT_PARAMETER = 1;
0159:
0160:            /** Marker for externally redirected 404 uri's. */
0161:            public static final String EXPORT_MARKER = "exporturi";
0162:
0163:            /** Time given (in seconds) to the static export handler to finish a publish task. */
0164:            public static final int HANDLER_FINISH_TIME = 60;
0165:
0166:            /** Cache value to indicate a true 404 error. */
0167:            private static final String CACHEVALUE_404 = "?404";
0168:
0169:            /** The log object for this class. */
0170:            private static final Log LOG = CmsLog
0171:                    .getLog(CmsStaticExportManager.class);
0172:
0173:            /** HTTP header Accept-Charset. */
0174:            private String m_acceptCharsetHeader;
0175:
0176:            /** HTTP header Accept-Language. */
0177:            private String m_acceptLanguageHeader;
0178:
0179:            /** Cache for the export links. */
0180:            private Map m_cacheExportLinks;
0181:
0182:            /** Cache for the export uris. */
0183:            private Map m_cacheExportUris;
0184:
0185:            /** Cache for the online links. */
0186:            private Map m_cacheOnlineLinks;
0187:
0188:            /** Cache for the secure links. */
0189:            private Map m_cacheSecureLinks;
0190:
0191:            /** OpenCms default charset header. */
0192:            private String m_defaultAcceptCharsetHeader;
0193:
0194:            /** OpenCms default locale header. */
0195:            private String m_defaultAcceptLanguageHeader;
0196:
0197:            /** Matcher for  selecting those resources which should be part of the static export. */
0198:            private CmsExportFolderMatcher m_exportFolderMatcher;
0199:
0200:            /** List of export resources which should be part of the static export. */
0201:            private List m_exportFolders;
0202:
0203:            /** The additional http headers for the static export. */
0204:            private List m_exportHeaders;
0205:
0206:            /** List of all resources that have the "exportname" property set. */
0207:            private Map m_exportnameResources;
0208:
0209:            /** Indicates if <code>true</code> is the default value for the property "export". */
0210:            private boolean m_exportPropertyDefault;
0211:
0212:            /** Indicates if links in the static export should be relative. */
0213:            private boolean m_exportRelativeLinks;
0214:
0215:            /** List of export rules. */
0216:            private List m_exportRules;
0217:
0218:            /** List of export suffixes where the "export" property default is always <code>true</code>. */
0219:            private List m_exportSuffixes;
0220:
0221:            /** Temporary variable for reading the xml config file. */
0222:            private CmsStaticExportExportRule m_exportTmpRule;
0223:
0224:            /** Export url to send internal requests to. */
0225:            private String m_exportUrl;
0226:
0227:            /** Export url with unsubstituted context values. */
0228:            private String m_exportUrlConfigured;
0229:
0230:            /** Export url to send internal requests to without http://servername. */
0231:            private String m_exportUrlPrefix;
0232:
0233:            /** Boolean value if the export is a full static export. */
0234:            private boolean m_fullStaticExport;
0235:
0236:            /** Handler class for static export. */
0237:            private I_CmsStaticExportHandler m_handler;
0238:
0239:            /** The configured link substitution handler. */
0240:            private I_CmsLinkSubstitutionHandler m_linkSubstitutionHandler;
0241:
0242:            /** Lock object for write access to the {@link #cmsEvent(CmsEvent)} method. */
0243:            private Object m_lockCmsEvent;
0244:
0245:            /** Lock object for export folder deletion in {@link #scrubExportFolders(I_CmsReport)}. */
0246:            private Object m_lockScrubExportFolders;
0247:
0248:            /** Lock object for write access to the {@link #m_exportnameResources} map in {@link #setExportnames()}. */
0249:            private Object m_lockSetExportnames;
0250:
0251:            /** Indicates if the quick static export for plain resources is enabled. */
0252:            private boolean m_quickPlainExport;
0253:
0254:            /** Remote address. */
0255:            private String m_remoteAddr;
0256:
0257:            /** Prefix to use for exported files. */
0258:            private String m_rfsPrefix;
0259:
0260:            /** Prefix to use for exported files with unsubstituted context values. */
0261:            private String m_rfsPrefixConfigured;
0262:
0263:            /** List of configured rfs rules. */
0264:            private List m_rfsRules;
0265:
0266:            /** Temporary variable for reading the xml config file. */
0267:            private CmsStaticExportRfsRule m_rfsTmpRule;
0268:
0269:            /** The number of backups stored for the export folder. */
0270:            private Integer m_staticExportBackups;
0271:
0272:            /** Indicates if the static export is enabled or disabled. */
0273:            private boolean m_staticExportEnabled;
0274:
0275:            /** The path to where the static export will be written. */
0276:            private String m_staticExportPath;
0277:
0278:            /** The path to where the static export will be written without the complete rfs path. */
0279:            private String m_staticExportPathConfigured;
0280:
0281:            /** The path to where the static export will be written during the static export process. */
0282:            private String m_staticExportWorkPath;
0283:
0284:            /** The path to where the static export will be written during the static export process without the complete rfs path. */
0285:            private String m_staticExportWorkPathConfigured;
0286:
0287:            /** Vfs Name of a resource used to do a "static export required" test. */
0288:            private String m_testResource;
0289:
0290:            /** If there are several identical export paths the usage of temporary directories has to be disabled. */
0291:            private boolean m_useTempDirs = true;
0292:
0293:            /** Prefix to use for internal OpenCms files. */
0294:            private String m_vfsPrefix;
0295:
0296:            /** Prefix to use for internal OpenCms files with unsubstituted context values. */
0297:            private String m_vfsPrefixConfigured;
0298:
0299:            /**
0300:             * Creates a new static export property object.<p>
0301:             * 
0302:             */
0303:            public CmsStaticExportManager() {
0304:
0305:                m_lockCmsEvent = new Object();
0306:                m_lockScrubExportFolders = new Object();
0307:                m_lockSetExportnames = new Object();
0308:                m_exportSuffixes = new ArrayList();
0309:                m_exportFolders = new ArrayList();
0310:                m_exportHeaders = new ArrayList();
0311:                m_rfsRules = new ArrayList();
0312:                m_exportRules = new ArrayList();
0313:                m_exportTmpRule = new CmsStaticExportExportRule("", "");
0314:                m_rfsTmpRule = new CmsStaticExportRfsRule("", "", "", "", "",
0315:                        "", null, null);
0316:                m_fullStaticExport = false;
0317:            }
0318:
0319:            /**
0320:             * Adds a new export rule to the configuration.<p>
0321:             * 
0322:             * @param name the name of the rule
0323:             * @param description the description for the rule
0324:             */
0325:            public void addExportRule(String name, String description) {
0326:
0327:                m_exportRules.add(new CmsStaticExportExportRule(name,
0328:                        description, m_exportTmpRule.getModifiedResources(),
0329:                        m_exportTmpRule.getExportResourcePatterns()));
0330:                m_exportTmpRule = new CmsStaticExportExportRule("", "");
0331:            }
0332:
0333:            /**
0334:             * Adds a regex to the latest export rule.<p>
0335:             * 
0336:             * @param regex the regex to add
0337:             */
0338:            public void addExportRuleRegex(String regex) {
0339:
0340:                m_exportTmpRule.addModifiedResource(regex);
0341:            }
0342:
0343:            /**
0344:             * Adds a export uri to the latest export rule.<p>
0345:             * 
0346:             * @param exportUri the export uri to add
0347:             */
0348:            public void addExportRuleUri(String exportUri) {
0349:
0350:                m_exportTmpRule.addExportResourcePattern(exportUri);
0351:            }
0352:
0353:            /**
0354:             * Adds a new rfs rule to the configuration.<p>
0355:             * 
0356:             * @param name the name of the rule
0357:             * @param description the description for the rule
0358:             * @param source the source regex
0359:             * @param rfsPrefix the url prefix
0360:             * @param exportPath the rfs export path
0361:             * @param exportWorkPath the rfs export work path
0362:             * @param exportBackups the number of backups
0363:             * @param useRelativeLinks the relative links value
0364:             */
0365:            public void addRfsRule(String name, String description,
0366:                    String source, String rfsPrefix, String exportPath,
0367:                    String exportWorkPath, String exportBackups,
0368:                    String useRelativeLinks) {
0369:
0370:                if ((m_staticExportPathConfigured != null)
0371:                        && exportPath.equals(m_staticExportPathConfigured)) {
0372:                    m_useTempDirs = false;
0373:                }
0374:                Iterator itRules = m_rfsRules.iterator();
0375:                while (m_useTempDirs && itRules.hasNext()) {
0376:                    CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) itRules
0377:                            .next();
0378:                    if (exportPath.equals(rule.getExportPathConfigured())) {
0379:                        m_useTempDirs = false;
0380:                    }
0381:                }
0382:                Boolean relativeLinks = (useRelativeLinks == null ? null
0383:                        : Boolean.valueOf(useRelativeLinks));
0384:                Integer backups = (exportBackups == null ? null : Integer
0385:                        .valueOf(exportBackups));
0386:
0387:                m_rfsRules
0388:                        .add(new CmsStaticExportRfsRule(name, description,
0389:                                source, rfsPrefix, exportPath, exportWorkPath,
0390:                                backups, relativeLinks, m_rfsTmpRule
0391:                                        .getRelatedSystemResources()));
0392:                m_rfsTmpRule = new CmsStaticExportRfsRule("", "", "", "", "",
0393:                        "", null, null);
0394:            }
0395:
0396:            /**
0397:             * Adds a regex of related system resources to the latest rfs-rule.<p>
0398:             * 
0399:             * @param regex the regex to add
0400:             */
0401:            public void addRfsRuleSystemRes(String regex) {
0402:
0403:                m_rfsTmpRule.addRelatedSystemRes(regex);
0404:            }
0405:
0406:            /**
0407:             * Caches a calculated export uri.<p>
0408:             * 
0409:             * @param rfsName the name of the resource in the "real" file system
0410:             * @param vfsName the name of the resource in the VFS
0411:             * @param parameters the optional parameters for the generation of the resource
0412:             */
0413:            public void cacheExportUri(String rfsName, String vfsName,
0414:                    String parameters) {
0415:
0416:                m_cacheExportUris.put(rfsName, new CmsStaticExportData(vfsName,
0417:                        parameters));
0418:            }
0419:
0420:            /**
0421:             * Caches a calculated online link.<p>
0422:             * 
0423:             * @param linkName the link
0424:             * @param vfsName the name of the VFS resource 
0425:             */
0426:            public void cacheOnlineLink(Object linkName, Object vfsName) {
0427:
0428:                m_cacheOnlineLinks.put(linkName, vfsName);
0429:            }
0430:
0431:            /**
0432:             * Implements the CmsEvent interface,
0433:             * the static export properties uses the events to clear 
0434:             * the list of cached keys in case a project is published.<p>
0435:             *
0436:             * @param event CmsEvent that has occurred
0437:             */
0438:            public void cmsEvent(CmsEvent event) {
0439:
0440:                if (!isStaticExportEnabled()) {
0441:                    if (LOG.isWarnEnabled()) {
0442:                        LOG.warn(Messages.get().getBundle().key(
0443:                                Messages.LOG_STATIC_EXPORT_DISABLED_0));
0444:                    }
0445:                    return;
0446:                }
0447:                I_CmsReport report = null;
0448:                Map data = event.getData();
0449:                if (data != null) {
0450:                    report = (I_CmsReport) data
0451:                            .get(I_CmsEventListener.KEY_REPORT);
0452:                }
0453:                if (report == null) {
0454:                    report = new CmsLogReport(CmsLocaleManager
0455:                            .getDefaultLocale(), getClass());
0456:                }
0457:                switch (event.getType()) {
0458:                case I_CmsEventListener.EVENT_UPDATE_EXPORTS:
0459:                    scrubExportFolders(report);
0460:                    clearCaches(event);
0461:                    break;
0462:                case I_CmsEventListener.EVENT_PUBLISH_PROJECT:
0463:                    if (data == null) {
0464:                        if (LOG.isErrorEnabled()) {
0465:                            LOG.error(Messages.get().getBundle().key(
0466:                                    Messages.ERR_EMPTY_EVENT_DATA_0));
0467:                        }
0468:                        return;
0469:                    }
0470:                    // event data contains a list of the published resources
0471:                    CmsUUID publishHistoryId = new CmsUUID((String) data
0472:                            .get(I_CmsEventListener.KEY_PUBLISHID));
0473:                    if (LOG.isDebugEnabled()) {
0474:                        LOG.debug(Messages.get().getBundle().key(
0475:                                Messages.LOG_EVENT_PUBLISH_PROJECT_1,
0476:                                publishHistoryId));
0477:                    }
0478:                    synchronized (m_lockCmsEvent) {
0479:                        getHandler().performEventPublishProject(
0480:                                publishHistoryId, report);
0481:                    }
0482:                    clearCaches(event);
0483:
0484:                    if (LOG.isDebugEnabled()) {
0485:                        LOG.debug(Messages.get().getBundle().key(
0486:                                Messages.LOG_EVENT_PUBLISH_PROJECT_FINISHED_1,
0487:                                publishHistoryId));
0488:                    }
0489:
0490:                    break;
0491:                case I_CmsEventListener.EVENT_CLEAR_CACHES:
0492:                    clearCaches(event);
0493:                    break;
0494:                default:
0495:                    // no operation
0496:                }
0497:            }
0498:
0499:            /**
0500:             * Exports the requested uri and at the same time writes the uri to the response output stream
0501:             * if required.<p>
0502:             * 
0503:             * @param req the current request
0504:             * @param res the current response
0505:             * @param cms an initialized cms context (should be initialized with the "Guest" user only)
0506:             * @param data the static export data set
0507:             * 
0508:             * @return status code of the export operation, status codes are the same as http status codes (200,303,304)
0509:             * 
0510:             * @throws CmsException in case of errors accessing the VFS
0511:             * @throws ServletException in case of errors accessing the servlet 
0512:             * @throws IOException in case of errors writing to the export output stream
0513:             * @throws CmsStaticExportException if static export is disabled
0514:             */
0515:            public int export(HttpServletRequest req, HttpServletResponse res,
0516:                    CmsObject cms, CmsStaticExportData data)
0517:                    throws CmsException, IOException, ServletException,
0518:                    CmsStaticExportException {
0519:
0520:                String vfsName = data.getVfsName();
0521:                String rfsName = data.getRfsName();
0522:                CmsResource resource = data.getResource();
0523:
0524:                // cut the site root from the vfsName and switch to the correct site
0525:                String siteRoot = OpenCms.getSiteManager().getSiteRoot(vfsName);
0526:
0527:                CmsI18nInfo i18nInfo = OpenCms.getLocaleManager().getI18nInfo(
0528:                        req, cms.getRequestContext().currentUser(),
0529:                        cms.getRequestContext().currentProject(), vfsName);
0530:
0531:                String remoteAddr = m_remoteAddr;
0532:                if (remoteAddr == null) {
0533:                    remoteAddr = CmsContextInfo.LOCALHOST;
0534:                }
0535:                CmsContextInfo contextInfo = new CmsContextInfo(cms
0536:                        .getRequestContext().currentUser(), cms
0537:                        .getRequestContext().currentProject(), vfsName, "/",
0538:                        i18nInfo.getLocale(), i18nInfo.getEncoding(),
0539:                        remoteAddr, CmsContextInfo.CURRENT_TIME, cms
0540:                                .getRequestContext().getOuFqn());
0541:
0542:                cms = OpenCms.initCmsObject(null, contextInfo);
0543:
0544:                if (siteRoot != null) {
0545:                    vfsName = vfsName.substring(siteRoot.length());
0546:                } else {
0547:                    siteRoot = "/";
0548:                }
0549:
0550:                if (LOG.isDebugEnabled()) {
0551:                    LOG.debug(Messages.get().getBundle().key(
0552:                            Messages.LOG_STATIC_EXPORT_SITE_ROOT_2, siteRoot,
0553:                            vfsName));
0554:                }
0555:                cms.getRequestContext().setSiteRoot(siteRoot);
0556:
0557:                String oldUri = null;
0558:
0559:                // this flag signals if the export method is used for "on demand" or "after publish". 
0560:                // if no request and result stream are available, it was called during "export on publish"
0561:                boolean exportOnDemand = ((req != null) && (res != null));
0562:
0563:                CmsStaticExportResponseWrapper wrapRes = null;
0564:                if (res != null) {
0565:                    wrapRes = new CmsStaticExportResponseWrapper(res);
0566:                }
0567:                if (LOG.isDebugEnabled()) {
0568:                    LOG.debug(Messages.get().getBundle().key(
0569:                            Messages.LOG_SE_RESOURCE_START_1, data));
0570:                }
0571:
0572:                CmsFile file;
0573:                // read vfs resource
0574:                if (resource.isFile()) {
0575:                    file = cms.readFile(vfsName);
0576:                } else {
0577:                    file = cms.readFile(OpenCms.initResource(cms, vfsName, req,
0578:                            wrapRes));
0579:                    if (cms.existsResource(vfsName + file.getName())) {
0580:                        vfsName = vfsName + file.getName();
0581:                    }
0582:                    rfsName += EXPORT_DEFAULT_FILE;
0583:                }
0584:
0585:                // check loader id for resource
0586:                I_CmsResourceLoader loader = OpenCms.getResourceManager()
0587:                        .getLoader(file);
0588:                if ((loader == null) || (!loader.isStaticExportEnabled())) {
0589:                    Object[] arguments = new Object[] { vfsName,
0590:                            new Integer(file.getTypeId()) };
0591:                    throw new CmsStaticExportException(Messages.get()
0592:                            .container(Messages.ERR_EXPORT_NOT_SUPPORTED_2,
0593:                                    arguments));
0594:                }
0595:
0596:                // ensure we have exactly the same setup as if called "the usual way"
0597:                // we only have to do this in case of the static export on demand
0598:                if (exportOnDemand) {
0599:                    String mimetype = OpenCms.getResourceManager().getMimeType(
0600:                            file.getName(),
0601:                            cms.getRequestContext().getEncoding());
0602:                    if (wrapRes != null) {
0603:                        wrapRes.setContentType(mimetype);
0604:                    }
0605:                    oldUri = cms.getRequestContext().getUri();
0606:                    cms.getRequestContext().setUri(vfsName);
0607:                }
0608:
0609:                // do the export
0610:                int status = -1;
0611:                // only export those resource where the export property is set
0612:                if (isExportLink(cms, vfsName)) {
0613:                    CmsLocaleManager locManager = OpenCms.getLocaleManager();
0614:                    List locales = locManager.getDefaultLocales(cms, vfsName);
0615:                    boolean exported = false;
0616:                    boolean matched = false;
0617:                    // iterate over all rules
0618:                    Iterator it = getRfsRules().iterator();
0619:                    while (it.hasNext()) {
0620:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
0621:                                .next();
0622:                        // normal case
0623:                        boolean export = rule.getSource().matcher(
0624:                                siteRoot + vfsName).matches();
0625:                        matched |= export;
0626:                        // system folder case
0627:                        export |= (vfsName
0628:                                .startsWith(CmsWorkplace.VFS_PATH_SYSTEM) && rule
0629:                                .match(vfsName));
0630:                        if (export) {
0631:                            // the resource has to exported for this rule
0632:                            CmsObject locCms = cms;
0633:                            Locale locale = CmsLocaleManager.getLocale(rule
0634:                                    .getName());
0635:                            if (locales.contains(locale)) {
0636:                                // if the locale is in the default locales for the resource
0637:                                // so adjust the locale to use for exporting
0638:                                CmsContextInfo ctxInfo = new CmsContextInfo(cms
0639:                                        .getRequestContext());
0640:                                ctxInfo.setLocale(locale);
0641:                                locCms = OpenCms.initCmsObject(cms, ctxInfo);
0642:                            }
0643:                            // read the content in the matching locale
0644:                            byte[] content = loader.export(locCms, file, req,
0645:                                    wrapRes);
0646:                            if (content != null) {
0647:                                // write to rfs
0648:                                exported = true;
0649:                                String locRfsName = rfsName;
0650:                                if (locales.contains(locale)) {
0651:                                    locRfsName = rule.getLocalizedRfsName(
0652:                                            rfsName, "/");
0653:                                }
0654:                                writeResource(req, rule.getExportPath(),
0655:                                        locRfsName, resource, content);
0656:                            }
0657:                        }
0658:                    }
0659:                    if (!matched) {
0660:                        // no rule matched
0661:                        String exportPath = getExportPath(siteRoot + vfsName);
0662:                        byte[] content = loader.export(cms, file, req, wrapRes);
0663:                        if (content != null) {
0664:                            exported = true;
0665:                            writeResource(req, exportPath, rfsName, resource,
0666:                                    content);
0667:                        }
0668:                    }
0669:                    if (exported) {
0670:                        // get the wrapper status that was set
0671:                        status = (wrapRes != null) ? wrapRes.getStatus() : -1;
0672:                        if (status < 0) {
0673:                            // the status was not set, assume everything is o.k.
0674:                            status = HttpServletResponse.SC_OK;
0675:                        }
0676:                    } else {
0677:                        // the resource was not written because it was not modified. 
0678:                        // set the status to not modified
0679:                        status = HttpServletResponse.SC_NOT_MODIFIED;
0680:                    }
0681:                } else {
0682:                    // the resource was not used for export, so return HttpServletResponse.SC_SEE_OTHER
0683:                    // as a signal for not exported resource
0684:                    status = HttpServletResponse.SC_SEE_OTHER;
0685:                }
0686:
0687:                // restore context
0688:                // we only have to do this in case of the static export on demand
0689:                if (exportOnDemand) {
0690:                    cms.getRequestContext().setUri(oldUri);
0691:                }
0692:
0693:                return status;
0694:            }
0695:
0696:            /**
0697:             * Starts a complete static export of all resources.<p>
0698:             * 
0699:             * @param purgeFirst flag to delete all resources in the export folder of the rfs
0700:             * @param report an I_CmsReport instance to print output message, or null to write messages to the log file   
0701:             * 
0702:             * @throws CmsException in case of errors accessing the VFS
0703:             * @throws IOException in case of errors writing to the export output stream
0704:             * @throws ServletException in case of errors accessing the servlet 
0705:             */
0706:            public synchronized void exportFullStaticRender(boolean purgeFirst,
0707:                    I_CmsReport report) throws CmsException, IOException,
0708:                    ServletException {
0709:
0710:                // set member to true to get temporary export paths for rules
0711:                m_fullStaticExport = true;
0712:                // save the real export path
0713:                String staticExportPathStore = m_staticExportPath;
0714:
0715:                if (m_useTempDirs) {
0716:                    // set the export path to the export work path
0717:                    m_staticExportPath = m_staticExportWorkPath;
0718:                }
0719:
0720:                // delete all old exports if the purgeFirst flag is set
0721:                if (purgeFirst) {
0722:                    Map eventData = new HashMap();
0723:                    eventData.put(I_CmsEventListener.KEY_REPORT, report);
0724:                    CmsEvent clearCacheEvent = new CmsEvent(
0725:                            I_CmsEventListener.EVENT_CLEAR_CACHES, eventData);
0726:                    OpenCms.fireCmsEvent(clearCacheEvent);
0727:
0728:                    scrubExportFolders(report);
0729:                    CmsObject cms = OpenCms.initCmsObject(OpenCms
0730:                            .getDefaultUsers().getUserExport());
0731:                    cms
0732:                            .deleteAllStaticExportPublishedResources(EXPORT_LINK_WITHOUT_PARAMETER);
0733:                    cms
0734:                            .deleteAllStaticExportPublishedResources(EXPORT_LINK_WITH_PARAMETER);
0735:                }
0736:
0737:                // do the export
0738:                CmsAfterPublishStaticExportHandler handler = new CmsAfterPublishStaticExportHandler();
0739:                // export everything
0740:                handler.doExportAfterPublish(null, report);
0741:
0742:                // set export path to the original one
0743:                m_staticExportPath = staticExportPathStore;
0744:
0745:                // set member to false for further exports
0746:                m_fullStaticExport = false;
0747:
0748:                // check if report contents no errors
0749:                if (m_useTempDirs && !report.hasError()) {
0750:                    // backup old export folders for default export 
0751:                    File staticExport = new File(m_staticExportPath);
0752:                    createExportBackupFolders(staticExport, m_staticExportPath,
0753:                            getExportBackups().intValue(), null);
0754:
0755:                    // change the name of the used temporary export folder to the original default export path
0756:                    File staticExportWork = new File(m_staticExportWorkPath);
0757:                    staticExportWork.renameTo(new File(m_staticExportPath));
0758:
0759:                    // backup old export folders of rule based exports
0760:                    Iterator it = m_rfsRules.iterator();
0761:                    while (it.hasNext()) {
0762:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
0763:                                .next();
0764:                        File staticExportRule = new File(rule.getExportPath());
0765:                        File staticExportWorkRule = new File(rule
0766:                                .getExportWorkPath());
0767:                        // only backup if a temporary folder exists for this rule
0768:                        if (staticExportWorkRule.exists()) {
0769:                            createExportBackupFolders(staticExportRule, rule
0770:                                    .getExportPath(), rule.getExportBackups()
0771:                                    .intValue(), OpenCms.getResourceManager()
0772:                                    .getFileTranslator().translateResource(
0773:                                            rule.getName()));
0774:                            staticExportWorkRule.renameTo(new File(rule
0775:                                    .getExportPath()));
0776:                        }
0777:                    }
0778:                } else if (report.hasError()) {
0779:                    report.println(Messages.get().container(
0780:                            Messages.ERR_EXPORT_NOT_SUCCESSFUL_0),
0781:                            I_CmsReport.FORMAT_WARNING);
0782:                }
0783:            }
0784:
0785:            /**
0786:             * Returns the accept-charset header used for internal requests.<p>
0787:             * 
0788:             * @return the accept-charset header
0789:             */
0790:            public String getAcceptCharsetHeader() {
0791:
0792:                return m_acceptCharsetHeader;
0793:            }
0794:
0795:            /**
0796:             * Returns the accept-language header used for internal requests.<p>
0797:             * 
0798:             * @return the accept-language header
0799:             */
0800:            public String getAcceptLanguageHeader() {
0801:
0802:                return m_acceptLanguageHeader;
0803:            }
0804:
0805:            /**
0806:             * Returns a cached export data for the given rfs name.<p>
0807:             * 
0808:             * Please note that this export data contains only the vfs name and the parameters,
0809:             * not the resource itself. It can therefore not directly be used as a return 
0810:             * value for the static export.<p>
0811:             * 
0812:             * @param rfsName the name of the resource in the real file system to get the cached vfs resource name for
0813:             * 
0814:             * @return a cached vfs resource name for the given rfs name, or <code>null</code> 
0815:             */
0816:            public CmsStaticExportData getCachedExportUri(String rfsName) {
0817:
0818:                return (CmsStaticExportData) m_cacheExportUris.get(rfsName);
0819:            }
0820:
0821:            /**
0822:             * Returns a cached link for the given vfs name.<p>
0823:             * 
0824:             * @param vfsName the name of the vfs resource to get the cached link for
0825:             * 
0826:             * @return a cached link for the given vfs name, or null 
0827:             */
0828:            public String getCachedOnlineLink(String vfsName) {
0829:
0830:                return (String) m_cacheOnlineLinks.get(vfsName);
0831:            }
0832:
0833:            /**
0834:             * Returns the key for the online, export and secure cache.<p>
0835:             * 
0836:             * @param siteRoot the site root of the resource
0837:             * @param uri the URI of the resource
0838:             * 
0839:             * @return a key for the cache 
0840:             */
0841:            public String getCacheKey(String siteRoot, String uri) {
0842:
0843:                return new StringBuffer(siteRoot).append(uri).toString();
0844:            }
0845:
0846:            /**
0847:             * Gets the default property value as a string representation.<p>
0848:             * 
0849:             * @return <code>"true"</code> or <code>"false"</code>
0850:             */
0851:            public String getDefault() {
0852:
0853:                return String.valueOf(m_exportPropertyDefault);
0854:            }
0855:
0856:            /**
0857:             * Returns the current default charset header.<p>
0858:             * 
0859:             * @return the current default charset header
0860:             */
0861:            public String getDefaultAcceptCharsetHeader() {
0862:
0863:                return m_defaultAcceptCharsetHeader;
0864:            }
0865:
0866:            /**
0867:             * Returns the current default locale header.<p>
0868:             * 
0869:             * @return the current default locale header
0870:             */
0871:            public String getDefaultAcceptLanguageHeader() {
0872:
0873:                return m_defaultAcceptLanguageHeader;
0874:            }
0875:
0876:            /**
0877:             * Returns the default prefix for exported links in the "real" file system.<p>
0878:             * 
0879:             * @return the default prefix for exported links in the "real" file system
0880:             */
0881:            public String getDefaultRfsPrefix() {
0882:
0883:                return m_rfsPrefix;
0884:            }
0885:
0886:            /**
0887:             * Returns the number of stored backups.<p>
0888:             * 
0889:             * @return the number of stored backups
0890:             */
0891:            public Integer getExportBackups() {
0892:
0893:                if (m_staticExportBackups != null) {
0894:                    return m_staticExportBackups;
0895:                }
0896:                // if backups not configured set to default value
0897:                return EXPORT_DEFAULT_BACKUPS;
0898:            }
0899:
0900:            /**
0901:             * Returns the export data for the request, if null is returned no export is required.<p>
0902:             * 
0903:             * @param request the request to check for export data
0904:             * @param cms an initialized cms context (should be initialized with the "Guest" user only
0905:             * 
0906:             * @return the export data for the request, if null is returned no export is required
0907:             */
0908:            public CmsStaticExportData getExportData(
0909:                    HttpServletRequest request, CmsObject cms) {
0910:
0911:                if (!isStaticExportEnabled()) {
0912:                    // export is disabled
0913:                    return null;
0914:                }
0915:
0916:                // build the rfs name for the export "on demand"
0917:                String rfsName = request.getParameter(EXPORT_MARKER);
0918:                if ((rfsName == null)) {
0919:                    rfsName = (String) request
0920:                            .getAttribute(EXPORT_ATTRIBUTE_ERROR_REQUEST_URI);
0921:                }
0922:
0923:                if (request.getHeader(CmsRequestUtil.HEADER_OPENCMS_EXPORT) != null) {
0924:                    // this is a request created by the static export and directly send to 404 handler
0925:                    // so remove the leading handler identification
0926:                    int prefix = rfsName.startsWith(getExportUrlPrefix()) ? getExportUrlPrefix()
0927:                            .length()
0928:                            : 0;
0929:                    if (prefix > 0) {
0930:                        rfsName = rfsName.substring(prefix);
0931:                    } else {
0932:                        return null;
0933:                    }
0934:                }
0935:
0936:                if (!isValidRfsName(rfsName)) {
0937:                    // this is not an export request, no further processing is required
0938:                    return null;
0939:                }
0940:
0941:                return getExportData(rfsName, null, cms);
0942:            }
0943:
0944:            /**
0945:             * Returns the export data for a requested resource, if null is returned no export is required.<p>
0946:             * 
0947:             * @param vfsName the VFS name of the resource requested
0948:             * @param cms an initialized cms context (should be initialized with the "Guest" user only
0949:             * 
0950:             * @return the export data for the request, if null is returned no export is required
0951:             */
0952:            public CmsStaticExportData getExportData(String vfsName,
0953:                    CmsObject cms) {
0954:
0955:                return getExportData(getRfsName(cms, vfsName), vfsName, cms);
0956:            }
0957:
0958:            /**
0959:             * Gets the export enabled value as a string representation.<p>
0960:             * 
0961:             * @return <code>"true"</code> or <code>"false"</code>
0962:             */
0963:            public String getExportEnabled() {
0964:
0965:                return String.valueOf(m_staticExportEnabled);
0966:            }
0967:
0968:            /**
0969:             * Returns the current folder matcher.<p>
0970:             * 
0971:             * @return the current folder matcher
0972:             */
0973:            public CmsExportFolderMatcher getExportFolderMatcher() {
0974:
0975:                return m_exportFolderMatcher;
0976:            }
0977:
0978:            /**
0979:             * Returns list of resources patterns which are part of the export.<p>
0980:             * 
0981:             * @return the of resources patterns which are part of the export.
0982:             */
0983:            public List getExportFolderPatterns() {
0984:
0985:                return Collections.unmodifiableList(m_exportFolders);
0986:            }
0987:
0988:            /**
0989:             * Returns specific http headers for the static export.<p>
0990:             * 
0991:             * If the header <code>Cache-Control</code> is set, OpenCms will not use its default headers.<p>
0992:             * 
0993:             * @return the list of http export headers
0994:             */
0995:            public List getExportHeaders() {
0996:
0997:                return Collections.unmodifiableList(m_exportHeaders);
0998:            }
0999:
1000:            /**
1001:             * Returns the list of all resources that have the "exportname" property set.<p>
1002:             * 
1003:             * @return the list of all resources that have the "exportname" property set
1004:             */
1005:            public Map getExportnames() {
1006:
1007:                return m_exportnameResources;
1008:            }
1009:
1010:            /**
1011:             * Returns the export path for the static export, that is the folder where the 
1012:             * static exported resources will be written to.<p>
1013:             * 
1014:             * The returned value will be a directory like prefix. The value is configured
1015:             * in the <code>opencms-importexport.xml</code> configuration file. An optimization
1016:             * of the configured value will be performed, where all relative path information is resolved
1017:             * (for example <code>/export/../static</code> will be resolved to <code>/export</code>. 
1018:             * Moreover, if the configured path ends with a <code>/</code>, this will be cut off 
1019:             * (for example <code>/export/</code> becomes <code>/export</code>.<p>
1020:             * 
1021:             * This is resource name based, and based on the rfs-rules defined in the 
1022:             * <code>opencms-importexport.xml</code> configuration file.<p>
1023:             * 
1024:             * @param vfsName the name of the resource to export
1025:             * 
1026:             * @return the export path for the static export, that is the folder where the
1027:             * 
1028:             * @see #getRfsPrefix(String)
1029:             * @see #getVfsPrefix()
1030:             */
1031:            public String getExportPath(String vfsName) {
1032:
1033:                if (vfsName != null) {
1034:                    Iterator it = m_rfsRules.iterator();
1035:                    while (it.hasNext()) {
1036:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
1037:                                .next();
1038:                        if (rule.getSource().matcher(vfsName).matches()) {
1039:                            return rule.getExportPath();
1040:                        }
1041:                    }
1042:                }
1043:                if (m_useTempDirs && isFullStaticExport()) {
1044:                    return getExportWorkPath();
1045:                }
1046:                return m_staticExportPath;
1047:            }
1048:
1049:            /**
1050:             * Returns the original configured export path for the static export without the complete rfs path, to be used 
1051:             * when re-writing the configuration.<p>
1052:             * 
1053:             * This is required <b>only</b> to serialize the configuration again exactly as it was configured.
1054:             * This method should <b>not</b> be used otherwise. Use <code>{@link #getExportPath(String)}</code>
1055:             * to obtain the export path to use when exporting.<p> 
1056:             * 
1057:             * @return the original configured export path for the static export without the complete rfs path
1058:             */
1059:            public String getExportPathForConfiguration() {
1060:
1061:                return m_staticExportPathConfigured;
1062:            }
1063:
1064:            /**
1065:             * Returns true if the default value for the resource property "export" is true.<p>
1066:             * 
1067:             * @return true if the default value for the resource property "export" is true
1068:             */
1069:            public boolean getExportPropertyDefault() {
1070:
1071:                return m_exportPropertyDefault;
1072:            }
1073:
1074:            /**
1075:             * Returns the export Rules.<p>
1076:             *
1077:             * @return the export Rules
1078:             */
1079:            public List getExportRules() {
1080:
1081:                return Collections.unmodifiableList(m_exportRules);
1082:            }
1083:
1084:            /**
1085:             * Gets the list of resource suffixes which will be exported by default.<p>
1086:             * 
1087:             * @return list of resource suffixes
1088:             */
1089:            public List getExportSuffixes() {
1090:
1091:                return m_exportSuffixes;
1092:            }
1093:
1094:            /**
1095:             * Returns the export URL used for internal requests for exporting resources that require a 
1096:             * request / response (like JSP).<p>
1097:             * 
1098:             * @return the export URL used for internal requests for exporting resources like JSP
1099:             */
1100:            public String getExportUrl() {
1101:
1102:                return m_exportUrl;
1103:            }
1104:
1105:            /**
1106:             * Returns the export URL used for internal requests with unsubstituted context values, to be used 
1107:             * when re-writing the configuration.<p>
1108:             * 
1109:             * This is required <b>only</b> to serialize the configuration again exactly as it was configured.
1110:             * This method should <b>not</b> be used otherwise. Use <code>{@link #getExportUrl()}</code>
1111:             * to obtain the export path to use when exporting.<p> 
1112:             * 
1113:             * @return the export URL used for internal requests with unsubstituted context values
1114:             */
1115:            public String getExportUrlForConfiguration() {
1116:
1117:                return m_exportUrlConfigured;
1118:            }
1119:
1120:            /**
1121:             * Returns the export URL used for internal requests for exporting resources that require a 
1122:             * request / response (like JSP) without http://servername.<p>
1123:             * 
1124:             * @return the export URL used for internal requests for exporting resources like JSP without http://servername
1125:             */
1126:            public String getExportUrlPrefix() {
1127:
1128:                return m_exportUrlPrefix;
1129:            }
1130:
1131:            /**
1132:             * Returns the export work path for the static export, that is the folder where the 
1133:             * static exported resources will be written to during the export process.<p>
1134:             * 
1135:             * @return the export work path for the static export
1136:             */
1137:            public String getExportWorkPath() {
1138:
1139:                return m_staticExportWorkPath;
1140:            }
1141:
1142:            /**
1143:             * Returns the original configured export work path for the static export without the complete rfs path, to be used 
1144:             * when re-writing the configuration.<p>
1145:             * 
1146:             * @return the original configured export work path for the static export without the complete rfs path
1147:             */
1148:            public String getExportWorkPathForConfiguration() {
1149:
1150:                if (m_staticExportWorkPathConfigured != null) {
1151:                    return m_staticExportWorkPathConfigured;
1152:                }
1153:                // if work path not configured set to default value
1154:                return EXPORT_DEFAULT_WORKPATH;
1155:            }
1156:
1157:            /**
1158:             * Returns the configured static export handler class.<p>
1159:             * 
1160:             * If not set, a new <code>{@link CmsAfterPublishStaticExportHandler}</code> is created and returned.<p>
1161:             * 
1162:             * @return the configured static export handler class
1163:             */
1164:            public I_CmsStaticExportHandler getHandler() {
1165:
1166:                if (m_handler == null) {
1167:                    setHandler(CmsOnDemandStaticExportHandler.class.getName());
1168:                }
1169:                return m_handler;
1170:            }
1171:
1172:            /**
1173:             * Returns the configured link substitution handler class.<p>
1174:             * 
1175:             * If not set, a new <code>{@link CmsDefaultLinkSubstitutionHandler}</code> is created and returned.<p>
1176:             * 
1177:             * @return the configured link substitution handler class
1178:             */
1179:            public I_CmsLinkSubstitutionHandler getLinkSubstitutionHandler() {
1180:
1181:                if (m_linkSubstitutionHandler == null) {
1182:                    setLinkSubstitutionHandler(CmsDefaultLinkSubstitutionHandler.class
1183:                            .getName());
1184:                }
1185:                return m_linkSubstitutionHandler;
1186:            }
1187:
1188:            /**
1189:             * Gets the plain export optimization value as a string representation.<p>
1190:             * 
1191:             * @return <code>"true"</code> or <code>"false"</code>
1192:             */
1193:            public String getPlainExportOptimization() {
1194:
1195:                return String.valueOf(m_quickPlainExport);
1196:            }
1197:
1198:            /**
1199:             * Returns true if the quick plain export is enabled.<p>
1200:             * 
1201:             * @return true if the quick plain export is enabled
1202:             */
1203:            public boolean getQuickPlainExport() {
1204:
1205:                return m_quickPlainExport;
1206:            }
1207:
1208:            /**
1209:             * Gets the relative links value as a string representation.<p>
1210:             * 
1211:             * @return <code>"true"</code> or <code>"false"</code>
1212:             */
1213:            public String getRelativeLinks() {
1214:
1215:                return String.valueOf(m_exportRelativeLinks);
1216:            }
1217:
1218:            /**
1219:             * Returns the remote address used for internal requests.<p>
1220:             * 
1221:             * @return the remote address
1222:             */
1223:            public String getRemoteAddr() {
1224:
1225:                return m_remoteAddr;
1226:            }
1227:
1228:            /**
1229:             * Returns the remote address.<p>
1230:             * 
1231:             * @return the remote address
1232:             */
1233:            public String getRemoteAddress() {
1234:
1235:                return m_remoteAddr;
1236:            }
1237:
1238:            /**
1239:             * Returns the static export rfs name for a given vfs resource.<p>
1240:             * 
1241:             * @param cms an initialized cms context
1242:             * @param vfsName the name of the vfs resource
1243:             * 
1244:             * @return the static export rfs name for a give vfs resource
1245:             * 
1246:             * @see #getVfsName(CmsObject, String)
1247:             * @see #getRfsName(CmsObject, String, String)
1248:             */
1249:            public String getRfsName(CmsObject cms, String vfsName) {
1250:
1251:                return getRfsName(cms, vfsName, null);
1252:            }
1253:
1254:            /**
1255:             * Returns the static export rfs name for a given vfs resource where the link to the 
1256:             * resource includes request parameters.<p>
1257:             * 
1258:             * @param cms an initialized cms context
1259:             * @param vfsName the name of the vfs resource
1260:             * @param parameters the parameters of the link pointing to the resource
1261:             * 
1262:             * @return the static export rfs name for a give vfs resource
1263:             */
1264:            public String getRfsName(CmsObject cms, String vfsName,
1265:                    String parameters) {
1266:
1267:                String rfsName = vfsName;
1268:                try {
1269:                    // check if the resource folder (or a parent folder) has the "exportname" property set
1270:                    CmsProperty exportNameProperty = cms.readPropertyObject(
1271:                            CmsResource.getFolderPath(rfsName),
1272:                            CmsPropertyDefinition.PROPERTY_EXPORTNAME, true);
1273:
1274:                    if (exportNameProperty.isNullProperty()) {
1275:                        // if "exportname" is not set we must add the site root 
1276:                        rfsName = cms.getRequestContext().addSiteRoot(rfsName);
1277:                    } else {
1278:                        // "exportname" property is set
1279:                        String exportname = exportNameProperty.getValue();
1280:                        if (exportname.charAt(0) != '/') {
1281:                            exportname = '/' + exportname;
1282:                        }
1283:                        if (exportname.charAt(exportname.length() - 1) != '/') {
1284:                            exportname = exportname + '/';
1285:                        }
1286:                        String value = null;
1287:                        boolean cont;
1288:                        String resourceName = rfsName;
1289:                        do {
1290:                            // find out where the export name was set, to replace these parent folders in the RFS name
1291:                            try {
1292:                                CmsProperty prop = cms
1293:                                        .readPropertyObject(
1294:                                                resourceName,
1295:                                                CmsPropertyDefinition.PROPERTY_EXPORTNAME,
1296:                                                false);
1297:                                if (prop.isIdentical(exportNameProperty)) {
1298:                                    // look for the right position in path 
1299:                                    value = prop.getValue();
1300:                                }
1301:                                cont = (value == null)
1302:                                        && (resourceName.length() > 1);
1303:                            } catch (CmsVfsResourceNotFoundException e) {
1304:                                // this is for publishing deleted resources 
1305:                                cont = (resourceName.length() > 1);
1306:                            } catch (CmsSecurityException se) {
1307:                                // a security exception (probably no read permission) we return the current result                      
1308:                                cont = false;
1309:                            }
1310:                            if (cont) {
1311:                                resourceName = CmsResource
1312:                                        .getParentFolder(resourceName);
1313:                            }
1314:                        } while (cont);
1315:                        rfsName = exportname
1316:                                + rfsName.substring(resourceName.length());
1317:                    }
1318:
1319:                    String extension = CmsFileUtil.getExtension(rfsName);
1320:                    // check if the VFS resource is a JSP page with a ".jsp" ending 
1321:                    // in this case the rfs name suffix must be build with special care,
1322:                    // usually it must be set to ".html"             
1323:                    boolean isJsp = extension.equals(".jsp");
1324:                    if (isJsp) {
1325:                        String suffix = null;
1326:                        try {
1327:                            CmsResource res = cms.readResource(vfsName);
1328:                            isJsp = (res.getTypeId() == CmsResourceTypeJsp
1329:                                    .getStaticTypeId());
1330:                            // if the resource is a plain resource then no change in suffix is required
1331:                            if (isJsp) {
1332:                                suffix = cms
1333:                                        .readPropertyObject(
1334:                                                vfsName,
1335:                                                CmsPropertyDefinition.PROPERTY_EXPORTSUFFIX,
1336:                                                true).getValue(".html");
1337:                            }
1338:                        } catch (CmsVfsResourceNotFoundException e) {
1339:                            // resource has been deleted, so we are not able to get the right extension from the properties
1340:                            // try to figure out the right extension from file system
1341:                            File rfsFile = new File(CmsFileUtil
1342:                                    .normalizePath(OpenCms
1343:                                            .getStaticExportManager()
1344:                                            .getExportPath(vfsName)
1345:                                            + rfsName));
1346:                            File parent = rfsFile.getParentFile();
1347:                            if (parent != null) {
1348:                                File[] paramVariants = parent
1349:                                        .listFiles(new CmsPrefixFileFilter(
1350:                                                rfsFile.getName()));
1351:                                if ((paramVariants != null)
1352:                                        && (paramVariants.length > 0)) {
1353:                                    // take the first
1354:                                    suffix = paramVariants[0].getAbsolutePath()
1355:                                            .substring(
1356:                                                    rfsFile.getAbsolutePath()
1357:                                                            .length());
1358:                                }
1359:                            } else {
1360:                                // if no luck, try the default extension
1361:                                suffix = ".html";
1362:                            }
1363:                        }
1364:                        if ((suffix != null)
1365:                                && !extension.equals(suffix.toLowerCase())) {
1366:                            rfsName += suffix;
1367:                            extension = suffix;
1368:                        }
1369:                    }
1370:                    if (parameters != null) {
1371:                        // build the RFS name for the link with parameters
1372:                        rfsName = CmsFileUtil.getRfsPath(rfsName, extension,
1373:                                parameters);
1374:                        // we have found a rfs name for a vfs resource with parameters, save it to the database
1375:                        try {
1376:                            cms.writeStaticExportPublishedResource(rfsName,
1377:                                    EXPORT_LINK_WITH_PARAMETER, parameters,
1378:                                    System.currentTimeMillis());
1379:                        } catch (CmsException e) {
1380:                            LOG.error(Messages.get().getBundle().key(
1381:                                    Messages.LOG_WRITE_FAILED_1, rfsName), e);
1382:                        }
1383:                    }
1384:                } catch (CmsException e) {
1385:                    if (LOG.isDebugEnabled()) {
1386:                        LOG.debug(e.getLocalizedMessage(), e);
1387:                    }
1388:                    // ignore exception, return vfsName as rfsName
1389:                    rfsName = vfsName;
1390:                }
1391:
1392:                // add export rfs prefix and return result
1393:                if (!vfsName.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) {
1394:                    return getRfsPrefix(
1395:                            cms.getRequestContext().addSiteRoot(vfsName))
1396:                            .concat(rfsName);
1397:                } else {
1398:                    // check if we are generating a link to a related resource in the same rfs rule
1399:                    String source = cms.getRequestContext().addSiteRoot(
1400:                            cms.getRequestContext().getUri());
1401:                    Iterator it = m_rfsRules.iterator();
1402:                    while (it.hasNext()) {
1403:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
1404:                                .next();
1405:                        if (rule.getSource().matcher(source).matches()
1406:                                && rule.match(vfsName)) {
1407:                            return rule.getRfsPrefix().concat(rfsName);
1408:                        }
1409:                    }
1410:                    // this is a link across rfs rules 
1411:                    return getRfsPrefix(
1412:                            cms.getRequestContext().getSiteRoot() + "/")
1413:                            .concat(rfsName);
1414:                }
1415:            }
1416:
1417:            /**
1418:             * Returns the prefix for exported links in the "real" file system.<p>
1419:             * 
1420:             * The returned value will be a directory like prefix. The value is configured
1421:             * in the <code>opencms-importexport.xml</code> configuration file. An optimization
1422:             * of the configured value will be performed, where all relative path information is resolved
1423:             * (for example <code>/export/../static</code> will be resolved to <code>/export</code>. 
1424:             * Moreover, if the configured path ends with a <code>/</code>, this will be cut off 
1425:             * (for example <code>/export/</code> becomes <code>/export</code>.<p>
1426:             * 
1427:             * This is resource name based, and based on the rfs-rules defined in the 
1428:             * <code>opencms-importexport.xml</code> configuration file.<p>
1429:             * 
1430:             * @param vfsName the name of the resource to export
1431:             * 
1432:             * @return the prefix for exported links in the "real" file system
1433:             * 
1434:             * @see #getExportPath(String)
1435:             * @see #getVfsPrefix()
1436:             */
1437:            public String getRfsPrefix(String vfsName) {
1438:
1439:                if (vfsName != null) {
1440:                    Iterator it = m_rfsRules.iterator();
1441:                    while (it.hasNext()) {
1442:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
1443:                                .next();
1444:                        if (rule.getSource().matcher(vfsName).matches()) {
1445:                            return rule.getRfsPrefix();
1446:                        }
1447:                    }
1448:                }
1449:                return m_rfsPrefix;
1450:            }
1451:
1452:            /**
1453:             * Returns the original configured prefix for exported links in the "real" file, to be used 
1454:             * when re-writing the configuration.<p>
1455:             * 
1456:             * This is required <b>only</b> to serialize the configuration again exactly as it was configured.
1457:             * This method should <b>not</b> be used otherwise. Use <code>{@link #getRfsPrefix(String)}</code>
1458:             * to obtain the rfs prefix to use for the exported links.<p> 
1459:             * 
1460:             * @return the original configured prefix for exported links in the "real" file
1461:             */
1462:            public String getRfsPrefixForConfiguration() {
1463:
1464:                return m_rfsPrefixConfigured;
1465:            }
1466:
1467:            /**
1468:             * Returns the rfs Rules.<p>
1469:             *
1470:             * @return the rfs Rules
1471:             */
1472:            public List getRfsRules() {
1473:
1474:                return Collections.unmodifiableList(m_rfsRules);
1475:            }
1476:
1477:            /**
1478:             * Returns the vfs name of the test resource.<p>
1479:             * 
1480:             * @return the vfs name of the test resource.
1481:             */
1482:            public String getTestResource() {
1483:
1484:                return m_testResource;
1485:            }
1486:
1487:            /**
1488:             * Returns the VFS name for the given RFS name, being the exact reverse of <code>{@link #getRfsName(CmsObject, String)}</code>.<p>
1489:             * 
1490:             * Returns <code>null</code> if no matching VFS resource can be found for the given RFS name.<p>
1491:             * 
1492:             * @param cms the current users OpenCms context
1493:             * @param rfsName the RFS name to get the VFS name for
1494:             * 
1495:             * @return the VFS name for the given RFS name, or <code>null</code> if the RFS name does not match to the VFS
1496:             * 
1497:             * @see #getRfsName(CmsObject, String)
1498:             */
1499:            public String getVfsName(CmsObject cms, String rfsName) {
1500:
1501:                CmsStaticExportData data = getExportData(rfsName, null, cms);
1502:                if (data != null) {
1503:                    String result = data.getVfsName();
1504:                    if ((result != null)
1505:                            && result.startsWith(cms.getRequestContext()
1506:                                    .getSiteRoot())) {
1507:                        result = result.substring(cms.getRequestContext()
1508:                                .getSiteRoot().length());
1509:                    }
1510:                    return result;
1511:                }
1512:                return null;
1513:            }
1514:
1515:            /**
1516:             * Returns the prefix for the internal in the VFS.<p>
1517:             * 
1518:             * The returned value will be a directory like prefix. The value is configured
1519:             * in the <code>opencms-importexport.xml</code> configuration file. An optimization
1520:             * of the configured value will be performed, where all relative path information is resolved
1521:             * (for example <code>/opencms/../mycms</code> will be resolved to <code>/mycms</code>. 
1522:             * Moreover, if the configured path ends with a <code>/</code>, this will be cut off 
1523:             * (for example <code>/opencms/</code> becomes <code>/opencms</code>.<p>
1524:             * 
1525:             * @return the prefix for the internal in the VFS
1526:             * 
1527:             * @see #getExportPath(String)
1528:             * @see #getRfsPrefix(String)
1529:             */
1530:            public String getVfsPrefix() {
1531:
1532:                return m_vfsPrefix;
1533:            }
1534:
1535:            /**
1536:             * Returns the original configured prefix for internal links in the VFS, to be used 
1537:             * when re-writing the configuration.<p>
1538:             * 
1539:             * This is required <b>only</b> to serialize the configuration again exactly as it was configured.
1540:             * This method should <b>not</b> be used otherwise. Use <code>{@link #getVfsPrefix()}</code>
1541:             * to obtain the VFS prefix to use for the internal links.<p> 
1542:             * 
1543:             * @return the original configured prefix for internal links in the VFS
1544:             */
1545:            public String getVfsPrefixForConfiguration() {
1546:
1547:                return m_vfsPrefixConfigured;
1548:            }
1549:
1550:            /**
1551:             * Initializes the static export manager with the OpenCms system configuration.<p>
1552:             * 
1553:             * @param cms an OpenCms context object
1554:             */
1555:            public void initialize(CmsObject cms) {
1556:
1557:                // initialize static export RFS path (relative to web application)
1558:                m_staticExportPath = normalizeExportPath(m_staticExportPathConfigured);
1559:                m_staticExportWorkPath = normalizeExportPath(getExportWorkPathForConfiguration());
1560:                if (m_staticExportPath.equals(OpenCms.getSystemInfo()
1561:                        .getWebApplicationRfsPath())) {
1562:                    throw new CmsIllegalArgumentException(Messages.get()
1563:                            .container(Messages.ERR_INVALID_EXPORT_PATH_0));
1564:                }
1565:                // initialize prefix variables
1566:                m_rfsPrefix = normalizeRfsPrefix(m_rfsPrefixConfigured);
1567:                Iterator itRfsRules = m_rfsRules.iterator();
1568:                while (itRfsRules.hasNext()) {
1569:                    CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) itRfsRules
1570:                            .next();
1571:                    try {
1572:                        rule.setExportPath(normalizeExportPath(rule
1573:                                .getExportPathConfigured()));
1574:                    } catch (CmsIllegalArgumentException e) {
1575:                        CmsLog.INIT.warn(e.getMessageContainer());
1576:                        rule.setExportPath(m_staticExportPath);
1577:                    }
1578:                    try {
1579:                        rule.setExportWorkPath(normalizeExportPath(rule
1580:                                .getExportWorkPathConfigured()));
1581:                    } catch (CmsIllegalArgumentException e) {
1582:                        CmsLog.INIT.warn(e.getMessageContainer());
1583:                        rule.setExportWorkPath(m_staticExportWorkPath);
1584:                    }
1585:                    rule.setRfsPrefix(normalizeRfsPrefix(rule
1586:                            .getRfsPrefixConfigured()));
1587:                }
1588:                m_vfsPrefix = insertContextStrings(m_vfsPrefixConfigured);
1589:                m_vfsPrefix = CmsFileUtil.normalizePath(m_vfsPrefix, '/');
1590:                if (CmsResource.isFolder(m_vfsPrefix)) {
1591:                    // ensure prefix does NOT end with a folder '/'
1592:                    m_vfsPrefix = m_vfsPrefix.substring(0,
1593:                            m_vfsPrefix.length() - 1);
1594:                }
1595:                if (CmsLog.INIT.isDebugEnabled()) {
1596:                    if (cms != null) {
1597:                        CmsLog.INIT.debug(Messages.get().getBundle().key(
1598:                                Messages.INIT_SE_MANAGER_CREATED_1, cms));
1599:                    } else {
1600:                        CmsLog.INIT.debug(Messages.get().getBundle().key(
1601:                                Messages.INIT_SE_MANAGER_CREATED_0));
1602:                    }
1603:                }
1604:
1605:                LRUMap lruMap1 = new LRUMap(2048);
1606:                m_cacheOnlineLinks = Collections.synchronizedMap(lruMap1);
1607:                // map must be of type "LRUMap" so that memory monitor can acecss all information
1608:                OpenCms.getMemoryMonitor().register(
1609:                        this .getClass().getName() + ".m_cacheOnlineLinks",
1610:                        lruMap1);
1611:
1612:                LRUMap lruMap2 = new LRUMap(2048);
1613:                m_cacheExportUris = Collections.synchronizedMap(lruMap2);
1614:                // map must be of type "LRUMap" so that memory monitor can acecss all information
1615:                OpenCms.getMemoryMonitor().register(
1616:                        this .getClass().getName() + ".m_cacheExportUris",
1617:                        lruMap2);
1618:
1619:                LRUMap lruMap3 = new LRUMap(2048);
1620:                m_cacheSecureLinks = Collections.synchronizedMap(lruMap3);
1621:                // map must be of type "LRUMap" so that memory monitor can acecss all information
1622:                OpenCms.getMemoryMonitor().register(
1623:                        this .getClass().getName() + ".m_cacheSecureLinks",
1624:                        lruMap3);
1625:
1626:                LRUMap lruMap4 = new LRUMap(2048);
1627:                m_cacheExportLinks = Collections.synchronizedMap(lruMap4);
1628:                // map must be of type "LRUMap" so that memory monitor can acecss all information
1629:                OpenCms.getMemoryMonitor().register(
1630:                        this .getClass().getName() + ".m_cacheExportLinks",
1631:                        lruMap4);
1632:
1633:                // register this object as event listener
1634:                OpenCms.addCmsEventListener(this , new int[] {
1635:                        I_CmsEventListener.EVENT_PUBLISH_PROJECT,
1636:                        I_CmsEventListener.EVENT_CLEAR_CACHES,
1637:                        I_CmsEventListener.EVENT_UPDATE_EXPORTS });
1638:
1639:                m_exportFolderMatcher = new CmsExportFolderMatcher(
1640:                        m_exportFolders, m_testResource);
1641:
1642:                // initialize "exportname" folders
1643:                setExportnames();
1644:
1645:                // get the default accept-language header value
1646:                m_defaultAcceptLanguageHeader = CmsAcceptLanguageHeaderParser
1647:                        .createLanguageHeader();
1648:
1649:                // get the default accept-charset header value
1650:                m_defaultAcceptCharsetHeader = OpenCms.getSystemInfo()
1651:                        .getDefaultEncoding();
1652:
1653:                // get the export url prefix
1654:                int pos = m_exportUrl.indexOf("://");
1655:                if (pos > 0) {
1656:                    // absolute link, remove http://servername
1657:                    int pos2 = m_exportUrl.indexOf('/', pos + 3);
1658:                    if (pos2 > 0) {
1659:                        m_exportUrlPrefix = m_exportUrl.substring(pos2);
1660:                    } else {
1661:                        // should never happen
1662:                        m_exportUrlPrefix = "";
1663:                    }
1664:                } else {
1665:                    m_exportUrlPrefix = m_exportUrl;
1666:                }
1667:                if (CmsLog.INIT.isInfoEnabled()) {
1668:                    if (isStaticExportEnabled()) {
1669:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1670:                                Messages.INIT_STATIC_EXPORT_ENABLED_0));
1671:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1672:                                Messages.INIT_EXPORT_DEFAULT_1,
1673:                                Boolean.valueOf(getExportPropertyDefault())));
1674:                        itRfsRules = m_rfsRules.iterator();
1675:                        while (itRfsRules.hasNext()) {
1676:                            CmsStaticExportRfsRule rfsRule = (CmsStaticExportRfsRule) itRfsRules
1677:                                    .next();
1678:                            CmsLog.INIT
1679:                                    .info(Messages
1680:                                            .get()
1681:                                            .getBundle()
1682:                                            .key(
1683:                                                    Messages.INIT_EXPORT_RFS_RULE_EXPORT_PATH_2,
1684:                                                    rfsRule.getSource(),
1685:                                                    rfsRule.getExportPath()));
1686:                            CmsLog.INIT
1687:                                    .info(Messages
1688:                                            .get()
1689:                                            .getBundle()
1690:                                            .key(
1691:                                                    Messages.INIT_EXPORT_RFS_RULE_RFS_PREFIX_2,
1692:                                                    rfsRule.getSource(),
1693:                                                    rfsRule.getRfsPrefix()));
1694:                            if (rfsRule.getUseRelativeLinks() != null) {
1695:                                if (rfsRule.getUseRelativeLinks()
1696:                                        .booleanValue()) {
1697:                                    CmsLog.INIT
1698:                                            .info(Messages
1699:                                                    .get()
1700:                                                    .getBundle()
1701:                                                    .key(
1702:                                                            Messages.INIT_EXPORT_RFS_RULE_RELATIVE_LINKS_1,
1703:                                                            rfsRule.getSource()));
1704:                                } else {
1705:                                    CmsLog.INIT
1706:                                            .info(Messages
1707:                                                    .get()
1708:                                                    .getBundle()
1709:                                                    .key(
1710:                                                            Messages.INIT_EXPORT_RFS_RULE_ABSOLUTE_LINKS_1,
1711:                                                            rfsRule.getSource()));
1712:                                }
1713:                            }
1714:                        }
1715:                        // default rule
1716:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1717:                                Messages.INIT_EXPORT_RFS_RULE_EXPORT_PATH_2,
1718:                                "/", m_staticExportPath));
1719:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1720:                                Messages.INIT_EXPORT_RFS_RULE_RFS_PREFIX_2,
1721:                                "/", m_rfsPrefix));
1722:                        if (m_exportRelativeLinks) {
1723:                            CmsLog.INIT
1724:                                    .info(Messages
1725:                                            .get()
1726:                                            .getBundle()
1727:                                            .key(
1728:                                                    Messages.INIT_EXPORT_RFS_RULE_RELATIVE_LINKS_1,
1729:                                                    "/"));
1730:                        } else {
1731:                            CmsLog.INIT
1732:                                    .info(Messages
1733:                                            .get()
1734:                                            .getBundle()
1735:                                            .key(
1736:                                                    Messages.INIT_EXPORT_RFS_RULE_ABSOLUTE_LINKS_1,
1737:                                                    "/"));
1738:                        }
1739:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1740:                                Messages.INIT_EXPORT_VFS_PREFIX_1,
1741:                                getVfsPrefix()));
1742:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1743:                                Messages.INIT_EXPORT_EXPORT_HANDLER_1,
1744:                                getHandler().getClass().getName()));
1745:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1746:                                Messages.INIT_EXPORT_URL_1, getExportUrl()));
1747:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1748:                                Messages.INIT_EXPORT_OPTIMIZATION_1,
1749:                                getPlainExportOptimization()));
1750:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1751:                                Messages.INIT_EXPORT_TESTRESOURCE_1,
1752:                                getTestResource()));
1753:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1754:                                Messages.INIT_LINKSUBSTITUTION_HANDLER_1,
1755:                                getLinkSubstitutionHandler().getClass()
1756:                                        .getName()));
1757:                    } else {
1758:                        CmsLog.INIT.info(Messages.get().getBundle().key(
1759:                                Messages.INIT_STATIC_EXPORT_DISABLED_0));
1760:                    }
1761:                }
1762:            }
1763:
1764:            /**
1765:             * Checks if the static export is required for the given VFS resource.<p>
1766:             * 
1767:             * Please note that the given OpenCms user context is NOT used to read the resource.
1768:             * The check for export is always done with the permissions of the "Export" user.
1769:             * The provided user context is just used to get the current site root.<p>
1770:             * 
1771:             * Since the "Export" user always operates in the "Online" project, the resource
1772:             * is also read from the "Online" project, not from the current project of the given 
1773:             * OpenCms context.<p>
1774:             * 
1775:             * @param cms the current users OpenCms context
1776:             * @param vfsName the VFS resource name to check
1777:             * 
1778:             * @return <code>true</code> if static export is required for the given VFS resource
1779:             */
1780:            public boolean isExportLink(CmsObject cms, String vfsName) {
1781:
1782:                boolean result = false;
1783:                if (isStaticExportEnabled()) {
1784:                    Boolean exportResource = (Boolean) m_cacheExportLinks
1785:                            .get(getCacheKey(cms.getRequestContext()
1786:                                    .getSiteRoot(), vfsName));
1787:                    if (exportResource == null) {
1788:                        try {
1789:                            // static export must always be checked with the export users permissions,
1790:                            // not the current users permissions
1791:                            CmsObject exportCms = OpenCms.initCmsObject(OpenCms
1792:                                    .getDefaultUsers().getUserExport());
1793:                            exportCms.getRequestContext().setSiteRoot(
1794:                                    cms.getRequestContext().getSiteRoot());
1795:                            // let's look up export property in VFS
1796:                            String exportValue = exportCms
1797:                                    .readPropertyObject(
1798:                                            vfsName,
1799:                                            CmsPropertyDefinition.PROPERTY_EXPORT,
1800:                                            true).getValue();
1801:                            if (exportValue == null) {
1802:                                // no setting found for "export" property
1803:                                if (getExportPropertyDefault()) {
1804:                                    // if the default is "true" we always export
1805:                                    result = true;
1806:                                } else {
1807:                                    // check if the resource is exportable by suffix
1808:                                    result = isSuffixExportable(vfsName);
1809:                                }
1810:                            } else {
1811:                                // "export" value found, if it was "true" we export
1812:                                result = Boolean.valueOf(exportValue)
1813:                                        .booleanValue();
1814:                            }
1815:                        } catch (Exception e) {
1816:                            // no export required (probably security issues, e.g. no access for export user)
1817:                        }
1818:                        m_cacheExportLinks.put(getCacheKey(cms
1819:                                .getRequestContext().getSiteRoot(), vfsName),
1820:                                Boolean.valueOf(result));
1821:                    } else {
1822:                        result = exportResource.booleanValue();
1823:                    }
1824:                }
1825:                return result;
1826:            }
1827:
1828:            /**
1829:             * Returns true if the export process is a full static export.<p>
1830:             *
1831:             * @return true if the export process is a full static export
1832:             */
1833:            public boolean isFullStaticExport() {
1834:
1835:                return m_fullStaticExport;
1836:            }
1837:
1838:            /**
1839:             * Returns <code>true</code> if the given VFS resource should be transported through a secure channel.<p>
1840:             * 
1841:             * The secure mode is only checked in the "Online" project. 
1842:             * If the given OpenCms context is currently not in the "Online" project,
1843:             * <code>false</code> is returned.<p>
1844:             * 
1845:             * The given resource is read from the site root of the provided OpenCms context.<p>
1846:             * 
1847:             * @param cms the current users OpenCms context
1848:             * @param vfsName the VFS resource name to check
1849:             * 
1850:             * @return <code>true</code> if the given VFS resource should be transported through a secure channel
1851:             * 
1852:             * @see #isSecureLink(CmsObject, String, String)
1853:             */
1854:            public boolean isSecureLink(CmsObject cms, String vfsName) {
1855:
1856:                if (!cms.getRequestContext().currentProject().isOnlineProject()) {
1857:                    return false;
1858:                }
1859:                Boolean secureResource = (Boolean) m_cacheSecureLinks
1860:                        .get(getCacheKey(cms.getRequestContext().getSiteRoot(),
1861:                                vfsName));
1862:                if (secureResource == null) {
1863:                    try {
1864:                        String secureProp = cms.readPropertyObject(vfsName,
1865:                                CmsPropertyDefinition.PROPERTY_SECURE, true)
1866:                                .getValue();
1867:                        secureResource = Boolean.valueOf(secureProp);
1868:                        // only cache result if read was successfull
1869:                        m_cacheSecureLinks.put(getCacheKey(cms
1870:                                .getRequestContext().getSiteRoot(), vfsName),
1871:                                secureResource);
1872:                    } catch (CmsVfsResourceNotFoundException e) {
1873:                        secureResource = Boolean.FALSE;
1874:                        // resource does not exist, no secure link will be required for any user
1875:                        m_cacheSecureLinks.put(getCacheKey(cms
1876:                                .getRequestContext().getSiteRoot(), vfsName),
1877:                                secureResource);
1878:                    } catch (Exception e) {
1879:                        // no secure link required (probably security issues, e.g. no access for current user)
1880:                        // however other users may be allowed to read the resource, so the result can't be cached
1881:                        secureResource = Boolean.FALSE;
1882:                    }
1883:                }
1884:                return secureResource.booleanValue();
1885:            }
1886:
1887:            /**
1888:             * Returns <code>true</code> if the given VFS resource that is located under the 
1889:             * given site root should be transported through a secure channel.<p>
1890:             * 
1891:             * @param cms the current users OpenCms context
1892:             * @param vfsName the VFS resource name to check
1893:             * @param siteRoot the site root where the the VFS resource should be read
1894:             * 
1895:             * @return <code>true</code> if the given VFS resource should be transported through a secure channel
1896:             * 
1897:             * @see #isSecureLink(CmsObject, String)
1898:             */
1899:            public boolean isSecureLink(CmsObject cms, String vfsName,
1900:                    String siteRoot) {
1901:
1902:                if (siteRoot == null) {
1903:                    return isSecureLink(cms, vfsName);
1904:                }
1905:
1906:                // the site root of the cms object has to be changed so that the property can be read   
1907:                String storedSiteRoot = cms.getRequestContext().getSiteRoot();
1908:                try {
1909:                    cms.getRequestContext().setSiteRoot(siteRoot);
1910:                    return isSecureLink(cms, vfsName);
1911:                } finally {
1912:                    cms.getRequestContext().setSiteRoot(storedSiteRoot);
1913:                }
1914:            }
1915:
1916:            /**
1917:             * Returns true if the static export is enabled.<p>
1918:             * 
1919:             * @return true if the static export is enabled
1920:             */
1921:            public boolean isStaticExportEnabled() {
1922:
1923:                return m_staticExportEnabled;
1924:            }
1925:
1926:            /**
1927:             * Returns true if the given resource name is exportable because of it's suffix.<p>
1928:             * 
1929:             * @param resourceName the name to check 
1930:             * @return true if the given resource name is exportable because of it's suffix
1931:             */
1932:            public boolean isSuffixExportable(String resourceName) {
1933:
1934:                if (resourceName == null) {
1935:                    return false;
1936:                }
1937:                int pos = resourceName.lastIndexOf('.');
1938:                if (pos >= 0) {
1939:                    String suffix = resourceName.substring(pos).toLowerCase();
1940:                    return m_exportSuffixes.contains(suffix);
1941:                }
1942:                return false;
1943:            }
1944:
1945:            /**
1946:             * Checks if we have to use temporary directories during export.<p>
1947:             * 
1948:             * @return <code>true</code> if using temporary directories
1949:             */
1950:            public boolean isUseTempDir() {
1951:
1952:                return m_useTempDirs;
1953:            }
1954:
1955:            /**
1956:             * Returns true if the links in the static export should be relative.<p>
1957:             * 
1958:             * @param vfsName the name of the resource to export
1959:             * 
1960:             * @return true if the links in the static export should be relative
1961:             */
1962:            public boolean relativeLinksInExport(String vfsName) {
1963:
1964:                if (vfsName != null) {
1965:                    Iterator it = m_rfsRules.iterator();
1966:                    while (it.hasNext()) {
1967:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
1968:                                .next();
1969:                        if (rule.getSource().matcher(vfsName).matches()) {
1970:                            return rule.getUseRelativeLinks() != null ? rule
1971:                                    .getUseRelativeLinks().booleanValue()
1972:                                    : m_exportRelativeLinks;
1973:                        }
1974:                    }
1975:                }
1976:                return m_exportRelativeLinks;
1977:            }
1978:
1979:            /**
1980:             * Sets the accept-charset header value.<p>
1981:             * 
1982:             * @param value accept-language header value
1983:             */
1984:            public void setAcceptCharsetHeader(String value) {
1985:
1986:                m_acceptCharsetHeader = value;
1987:            }
1988:
1989:            /**
1990:             * Sets the accept-language header value.<p>
1991:             * 
1992:             * @param value accept-language header value
1993:             */
1994:            public void setAcceptLanguageHeader(String value) {
1995:
1996:                m_acceptLanguageHeader = value;
1997:            }
1998:
1999:            /**
2000:             * Sets the default property value.<p>
2001:             * 
2002:             * @param value must be <code>true</code> or <code>false</code>
2003:             */
2004:            public void setDefault(String value) {
2005:
2006:                m_exportPropertyDefault = Boolean.valueOf(value).booleanValue();
2007:            }
2008:
2009:            /**
2010:             * Sets the number of backups for the static export.<p>
2011:             * 
2012:             * @param backup number of backups
2013:             */
2014:            public void setExportBackups(String backup) {
2015:
2016:                m_staticExportBackups = new Integer(backup);
2017:            }
2018:
2019:            /**
2020:             * Sets the export enabled value.<p>
2021:             * 
2022:             * @param value must be <code>true</code> or <code>false</code>
2023:             */
2024:            public void setExportEnabled(String value) {
2025:
2026:                m_staticExportEnabled = Boolean.valueOf(value).booleanValue();
2027:            }
2028:
2029:            /**
2030:             * Adds a resource pattern to the list of resources which are part of the export.<p>
2031:             * 
2032:             * @param folder the folder pattern to add to the list.
2033:             */
2034:            public void setExportFolderPattern(String folder) {
2035:
2036:                m_exportFolders.add(folder);
2037:            }
2038:
2039:            /**
2040:             * Sets specific http header for the static export.<p>
2041:             * 
2042:             * The format of the headers must be "header:value".<p> 
2043:             *  
2044:             * @param exportHeader a specific http header
2045:             */
2046:            public void setExportHeader(String exportHeader) {
2047:
2048:                if (CmsStringUtil.splitAsArray(exportHeader, ':').length == 2) {
2049:                    if (CmsLog.INIT.isInfoEnabled()) {
2050:                        CmsLog.INIT.info(Messages.get().getBundle().key(
2051:                                Messages.INIT_EXPORT_HEADERS_1, exportHeader));
2052:                    }
2053:                    m_exportHeaders.add(exportHeader);
2054:                } else {
2055:                    if (CmsLog.INIT.isWarnEnabled()) {
2056:                        CmsLog.INIT.warn(Messages.get().getBundle().key(
2057:                                Messages.INIT_INVALID_HEADER_1, exportHeader));
2058:                    }
2059:                }
2060:            }
2061:
2062:            /**
2063:             * Sets the path where the static export is written.<p>
2064:             * 
2065:             * @param path the path where the static export is written
2066:             */
2067:            public void setExportPath(String path) {
2068:
2069:                m_staticExportPathConfigured = path;
2070:            }
2071:
2072:            /**
2073:             * Adds a suffix to the list of resource suffixes which will be exported by default.<p>
2074:             * 
2075:             * @param suffix the suffix to add to the list.
2076:             */
2077:            public void setExportSuffix(String suffix) {
2078:
2079:                m_exportSuffixes.add(suffix.toLowerCase());
2080:            }
2081:
2082:            /**
2083:             * Sets the export url.<p>
2084:             * 
2085:             * @param url the export url
2086:             */
2087:            public void setExportUrl(String url) {
2088:
2089:                m_exportUrl = insertContextStrings(url);
2090:                m_exportUrlConfigured = url;
2091:            }
2092:
2093:            /**
2094:             * Sets the path where the static export is temporarily written.<p>
2095:             * 
2096:             * @param path the path where the static export is temporarily written
2097:             */
2098:            public void setExportWorkPath(String path) {
2099:
2100:                m_staticExportWorkPathConfigured = path;
2101:            }
2102:
2103:            /**
2104:             * Sets the link substitution handler class.<p>
2105:             * 
2106:             * @param handlerClassName the link substitution handler class name
2107:             */
2108:            public void setHandler(String handlerClassName) {
2109:
2110:                try {
2111:                    m_handler = (I_CmsStaticExportHandler) Class.forName(
2112:                            handlerClassName).newInstance();
2113:                } catch (Exception e) {
2114:                    // should never happen
2115:                    LOG.error(e.getLocalizedMessage(), e);
2116:                }
2117:            }
2118:
2119:            /**
2120:             * Sets the static export handler class.<p>
2121:             * 
2122:             * @param handlerClassName the static export handler class name
2123:             */
2124:            public void setLinkSubstitutionHandler(String handlerClassName) {
2125:
2126:                try {
2127:                    m_linkSubstitutionHandler = (I_CmsLinkSubstitutionHandler) Class
2128:                            .forName(handlerClassName).newInstance();
2129:                } catch (Exception e) {
2130:                    // should never happen
2131:                    LOG.error(e.getLocalizedMessage(), e);
2132:                }
2133:            }
2134:
2135:            /**
2136:             * Sets the plain export optimization value.<p>
2137:             * 
2138:             * @param value must be <code>true</code> or <code>false</code>
2139:             */
2140:            public void setPlainExportOptimization(String value) {
2141:
2142:                m_quickPlainExport = Boolean.valueOf(value).booleanValue();
2143:            }
2144:
2145:            /**
2146:             * Sets the relative links value.<p>
2147:             * 
2148:             * @param value must be <code>true</code> or <code>false</code>
2149:             */
2150:            public void setRelativeLinks(String value) {
2151:
2152:                m_exportRelativeLinks = Boolean.valueOf(value).booleanValue();
2153:            }
2154:
2155:            /**
2156:             * Sets the remote address which will be used for internal requests during the static export.<p>
2157:             * 
2158:             * @param addr the remote address to be used
2159:             */
2160:            public void setRemoteAddr(String addr) {
2161:
2162:                m_remoteAddr = addr;
2163:            }
2164:
2165:            /**
2166:             * Sets the prefix for exported links in the "real" file system.<p>
2167:             * 
2168:             * @param rfsPrefix the prefix for exported links in the "real" file system
2169:             */
2170:            public void setRfsPrefix(String rfsPrefix) {
2171:
2172:                m_rfsPrefixConfigured = rfsPrefix;
2173:            }
2174:
2175:            /**
2176:             * Sets the test resource.<p>
2177:             *  
2178:             * @param testResource the vfs name of the test resource
2179:             */
2180:            public void setTestResource(String testResource) {
2181:
2182:                m_testResource = testResource;
2183:            }
2184:
2185:            /**
2186:             * Sets the prefix for internal links in the vfs.<p>
2187:             * 
2188:             * @param vfsPrefix the prefix for internal links in the vfs
2189:             */
2190:            public void setVfsPrefix(String vfsPrefix) {
2191:
2192:                m_vfsPrefixConfigured = vfsPrefix;
2193:            }
2194:
2195:            /**
2196:             * Shuts down all this static export manager.<p>
2197:             * 
2198:             * This is required since there may still be a thread running when the system is being shut down.<p>
2199:             */
2200:            public synchronized void shutDown() {
2201:
2202:                int count = 0;
2203:                // if the handler is still running, we must wait up to 30 seconds until it is finished
2204:                while ((count < HANDLER_FINISH_TIME) && m_handler.isBusy()) {
2205:                    count++;
2206:                    try {
2207:                        if (CmsLog.INIT.isInfoEnabled()) {
2208:                            CmsLog.INIT.info(Messages.get().getBundle().key(
2209:                                    Messages.INIT_STATIC_EXPORT_SHUTDOWN_3,
2210:                                    m_handler.getClass().getName(),
2211:                                    String.valueOf(count),
2212:                                    String.valueOf(HANDLER_FINISH_TIME)));
2213:                        }
2214:                        wait(1000);
2215:                    } catch (InterruptedException e) {
2216:                        // if interrupted we ignore the handler, this will produce some log messages but should be ok 
2217:                        count = HANDLER_FINISH_TIME;
2218:                    }
2219:                }
2220:
2221:                if (CmsLog.INIT.isInfoEnabled()) {
2222:                    CmsLog.INIT.info(Messages.get().getBundle()
2223:                            .key(Messages.INIT_SHUTDOWN_1,
2224:                                    this .getClass().getName()));
2225:                }
2226:
2227:            }
2228:
2229:            /**
2230:             * Clears the caches in the export manager.<p>
2231:             * 
2232:             * @param event the event that requested to clear the caches
2233:             */
2234:            protected void clearCaches(CmsEvent event) {
2235:
2236:                // synchronization of this method is not required as the individual maps are all synchronized maps anyway,
2237:                // and setExportnames() is doing it's own synchronization 
2238:
2239:                // flush all caches   
2240:                m_cacheOnlineLinks.clear();
2241:                m_cacheExportUris.clear();
2242:                m_cacheSecureLinks.clear();
2243:                m_cacheExportLinks.clear();
2244:                setExportnames();
2245:                if (LOG.isDebugEnabled()) {
2246:                    String eventType = "EVENT_CLEAR_CACHES";
2247:                    if (event.getType() != I_CmsEventListener.EVENT_CLEAR_CACHES) {
2248:                        eventType = "EVENT_PUBLISH_PROJECT";
2249:                    }
2250:                    LOG.debug(Messages.get().getBundle().key(
2251:                            Messages.LOG_FLUSHED_CACHES_1, eventType));
2252:                }
2253:            }
2254:
2255:            /**
2256:             * Creates the backup folders for the given export folder and deletes the oldest if the maximum number is reached.<p>
2257:             * 
2258:             * @param staticExport folder for which a new backup folder has to be created
2259:             * @param exportPath export path to create backup path out of it
2260:             * @param exportBackups number of maximum 
2261:             * @param ruleBackupExtension extension for rule based backups
2262:             */
2263:            protected void createExportBackupFolders(File staticExport,
2264:                    String exportPath, int exportBackups,
2265:                    String ruleBackupExtension) {
2266:
2267:                if (staticExport.exists()) {
2268:                    String backupFolderName = exportPath.substring(0,
2269:                            exportPath.lastIndexOf(File.separator) + 1);
2270:                    if (ruleBackupExtension != null) {
2271:                        backupFolderName = backupFolderName
2272:                                + EXPORT_BACKUP_FOLDER_NAME
2273:                                + ruleBackupExtension;
2274:                    } else {
2275:                        backupFolderName = backupFolderName
2276:                                + EXPORT_BACKUP_FOLDER_NAME;
2277:                    }
2278:                    for (int i = exportBackups; i > 0; i--) {
2279:                        File staticExportBackupOld = new File(backupFolderName
2280:                                + new Integer(i).toString());
2281:                        if (staticExportBackupOld.exists()) {
2282:                            if ((i + 1) > exportBackups) {
2283:                                // delete folder if it is the last backup folder
2284:                                CmsFileUtil
2285:                                        .purgeDirectory(staticExportBackupOld);
2286:                            } else {
2287:                                // set backup folder to the next backup folder name
2288:                                staticExportBackupOld
2289:                                        .renameTo(new File(backupFolderName
2290:                                                + new Integer(i + 1).toString()));
2291:                            }
2292:                        }
2293:                        // old export folder rename to first backup folder
2294:                        if (i == 1) {
2295:                            staticExport.renameTo(staticExportBackupOld);
2296:                        }
2297:                    }
2298:
2299:                    // if no backups will be stored the old export folder has to be deleted
2300:                    if (exportBackups == 0) {
2301:                        CmsFileUtil.purgeDirectory(staticExport);
2302:                    }
2303:                }
2304:            }
2305:
2306:            /**
2307:             * Creates the parent folder for a exported resource in the RFS.<p>
2308:             * 
2309:             * @param exportPath the path to export the file
2310:             * @param rfsName the rfs name of the resource
2311:             * 
2312:             * @throws CmsException if the folder could not be created
2313:             */
2314:            protected void createExportFolder(String exportPath, String rfsName)
2315:                    throws CmsException {
2316:
2317:                String exportFolderName = CmsFileUtil.normalizePath(exportPath
2318:                        + CmsResource.getFolderPath(rfsName));
2319:                File exportFolder = new File(exportFolderName);
2320:                if (!exportFolder.exists()) {
2321:                    if (!exportFolder.mkdirs()) {
2322:                        throw new CmsStaticExportException(Messages.get()
2323:                                .container(Messages.ERR_CREATE_FOLDER_1,
2324:                                        rfsName));
2325:
2326:                    }
2327:                }
2328:            }
2329:
2330:            /**
2331:             * Returns the export data for a requested resource, if null is returned no export is required.<p>
2332:             * 
2333:             * @param rfsName the RFS name of the resource requested
2334:             * @param vfsName the VFS name of the resource requested
2335:             * @param cms an initialized cms context (should be initialized with the "Guest" user only
2336:             * 
2337:             * @return the export data for the request, if null is returned no export is required
2338:             */
2339:            protected CmsStaticExportData getExportData(String rfsName,
2340:                    String vfsName, CmsObject cms) {
2341:
2342:                CmsResource resource = null;
2343:                String storedSiteRoot = cms.getRequestContext().getSiteRoot();
2344:                try {
2345:                    cms.getRequestContext().setSiteRoot("/");
2346:
2347:                    // cut export prefix from name
2348:                    rfsName = rfsName.substring(getRfsPrefixForRfsName(rfsName)
2349:                            .length());
2350:
2351:                    String parameters = null;
2352:                    if (vfsName == null) {
2353:                        // check if we have the result already in the cache
2354:                        CmsStaticExportData data = getCachedExportUri(rfsName);
2355:                        if (data != null) {
2356:                            vfsName = data.getVfsName();
2357:                            parameters = data.getParameters();
2358:                        }
2359:                    }
2360:
2361:                    if (vfsName != null) {
2362:                        // this export uri is already cached            
2363:                        if (CACHEVALUE_404 != vfsName) {
2364:                            // this uri can be exported
2365:                            try {
2366:                                resource = cms.readResource(vfsName);
2367:                            } catch (CmsException e) {
2368:                                // the resource has probably been deleted
2369:                                return null;
2370:                            }
2371:                            // valid cache entry, return export data object
2372:                            return new CmsStaticExportData(vfsName, rfsName,
2373:                                    resource, parameters);
2374:                        } else {
2375:                            // this uri can not be exported
2376:                            return null;
2377:                        }
2378:                    } else {
2379:                        // export uri not in cache, must look up the file in the VFS
2380:                        vfsName = getVfsNameInternal(cms, rfsName);
2381:                        if (vfsName != null) {
2382:                            try {
2383:                                resource = cms.readResource(vfsName);
2384:                            } catch (Exception e) {
2385:                                // ignore, still not found
2386:                            }
2387:                        }
2388:                        if (resource == null) {
2389:                            // it could be a translated resourcename with parameters, so make a lookup
2390:                            // in the published resources table
2391:                            try {
2392:                                parameters = cms
2393:                                        .readStaticExportPublishedResourceParameters(rfsName);
2394:                                // there was a match in the db table, so get the StaticExportData 
2395:                                if (CmsStringUtil.isNotEmpty(parameters)) {
2396:
2397:                                    // get the rfs base string without the parameter hashcode
2398:                                    String rfsBaseName = rfsName.substring(0,
2399:                                            rfsName.lastIndexOf('_'));
2400:
2401:                                    // get the vfs base name, which is later used to read the resource in the vfs
2402:                                    String vfsBaseName = getVfsNameInternal(
2403:                                            cms, rfsBaseName);
2404:
2405:                                    // everything is there, so read the resource in the vfs and build the static export data object
2406:                                    if (vfsBaseName != null) {
2407:                                        resource = cms
2408:                                                .readResource(vfsBaseName);
2409:                                        CmsStaticExportData exportData = new CmsStaticExportData(
2410:                                                vfsBaseName, rfsName, resource,
2411:                                                parameters);
2412:                                        cacheExportUri(rfsName, exportData
2413:                                                .getVfsName(), parameters);
2414:                                        return exportData;
2415:                                    }
2416:                                }
2417:                            } catch (CmsException e) {
2418:                                // ignore, resource does not exist
2419:                            }
2420:                            // no match found, nothing to export
2421:                            cacheExportUri(rfsName, CACHEVALUE_404, null);
2422:                            return null;
2423:                        } else {
2424:                            // found a resource to export
2425:                            cacheExportUri(rfsName, vfsName, null);
2426:                            return new CmsStaticExportData(vfsName, rfsName,
2427:                                    resource);
2428:                        }
2429:                    }
2430:                } finally {
2431:                    cms.getRequestContext().setSiteRoot(storedSiteRoot);
2432:                }
2433:            }
2434:
2435:            /**
2436:             * Returns the longest rfs prefix matching a given already translated rfs name.<p>
2437:             * 
2438:             * @param rfsName the rfs name
2439:             * 
2440:             * @return its rfs prefix
2441:             * 
2442:             * @see #getRfsPrefix(String)
2443:             */
2444:            protected String getRfsPrefixForRfsName(String rfsName) {
2445:
2446:                String retVal = "";
2447:                // default case
2448:                if (rfsName.startsWith(m_rfsPrefix + "/")) {
2449:                    retVal = m_rfsPrefix;
2450:                }
2451:                // additional rules
2452:                Iterator it = m_rfsRules.iterator();
2453:                while (it.hasNext()) {
2454:                    CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
2455:                            .next();
2456:                    String rfsPrefix = rule.getRfsPrefix();
2457:                    if (rfsName.startsWith(rfsPrefix + "/")
2458:                            && (retVal.length() < rfsPrefix.length())) {
2459:                        retVal = rfsPrefix;
2460:                    }
2461:                }
2462:                return retVal;
2463:            }
2464:
2465:            /**
2466:             * Returns the VFS name from a given RFS name.<p>
2467:             * 
2468:             * The RFS name must not contain the RFS prefix.<p>
2469:             * 
2470:             * @param cms an initialized OpenCms user context
2471:             * @param rfsName the name of the RFS resource
2472:             * 
2473:             * @return the name of the VFS resource
2474:             */
2475:            protected String getVfsNameInternal(CmsObject cms, String rfsName) {
2476:
2477:                String vfsName = null;
2478:                CmsResource resource;
2479:
2480:                boolean match = false;
2481:
2482:                try {
2483:                    resource = cms.readResource(cms.getRequestContext()
2484:                            .removeSiteRoot(rfsName));
2485:                    if (resource.isFolder() && !CmsResource.isFolder(rfsName)) {
2486:                        rfsName += '/';
2487:                    }
2488:                    vfsName = rfsName;
2489:                    match = true;
2490:                } catch (Throwable t) {
2491:                    // resource not found                   
2492:                }
2493:
2494:                if (!match) {
2495:                    // name of export resource could not be resolved by reading the resource directly,
2496:                    // now try to find a match with the "exportname" folders            
2497:                    Map exportnameFolders = getExportnames();
2498:                    Iterator i = exportnameFolders.entrySet().iterator();
2499:                    while (i.hasNext()) {
2500:                        Map.Entry entry = (Map.Entry) i.next();
2501:                        String exportName = (String) entry.getKey();
2502:                        if (rfsName.startsWith(exportName)) {
2503:                            // prefix match
2504:                            match = true;
2505:                            vfsName = "" + entry.getValue()
2506:                                    + rfsName.substring(exportName.length());
2507:                            try {
2508:                                resource = cms.readResource(vfsName);
2509:                                if (resource.isFolder()) {
2510:                                    if (!CmsResource.isFolder(rfsName)) {
2511:                                        rfsName += '/';
2512:                                    }
2513:                                    if (!CmsResource.isFolder(vfsName)) {
2514:                                        vfsName += '/';
2515:                                    }
2516:                                }
2517:                                break;
2518:                            } catch (CmsVfsResourceNotFoundException e) {
2519:                                // continue with trying out the other exportname to find a match (may be a multiple prefix)
2520:                                match = false;
2521:                                continue;
2522:                            } catch (CmsException e) {
2523:                                break;
2524:                            }
2525:                        }
2526:                    }
2527:                }
2528:
2529:                // finally check if its a modified jsp resource        
2530:                if (!match) {
2531:                    // first cut of the last extension
2532:                    int extPos = rfsName.lastIndexOf('.');
2533:                    if (extPos >= 0) {
2534:                        String cutName = rfsName.substring(0, extPos);
2535:                        int pos = cutName.lastIndexOf('.');
2536:                        if (pos >= 0) {
2537:                            // now check if remaining String ends with ".jsp"
2538:                            String extension = cutName.substring(pos)
2539:                                    .toLowerCase();
2540:                            if (".jsp".equals(extension)) {
2541:                                return getVfsNameInternal(cms, cutName);
2542:                            }
2543:                        }
2544:                    }
2545:                }
2546:                if (match) {
2547:                    return vfsName;
2548:                } else {
2549:                    return null;
2550:                }
2551:            }
2552:
2553:            /**
2554:             * Substitutes the ${CONTEXT_NAME} and ${SERVLET_NAME} in a path with the real values.<p>
2555:             * 
2556:             * @param path the path to substitute
2557:             * @return path with real context values
2558:             */
2559:            protected String insertContextStrings(String path) {
2560:
2561:                // create a new macro resolver
2562:                CmsMacroResolver resolver = CmsMacroResolver.newInstance();
2563:
2564:                // add special mappings for macros 
2565:                resolver.addMacro("CONTEXT_NAME", OpenCms.getSystemInfo()
2566:                        .getContextPath());
2567:                resolver.addMacro("SERVLET_NAME", OpenCms.getSystemInfo()
2568:                        .getServletPath());
2569:
2570:                // resolve the macros
2571:                return resolver.resolveMacros(path);
2572:            }
2573:
2574:            /**
2575:             * Returns true if the rfs Name match against any of the defined export urls.<p>
2576:             * 
2577:             * @param rfsName the rfs Name to validate
2578:             * 
2579:             * @return true if the rfs Name match against any of the defined export urls
2580:             */
2581:            protected boolean isValidRfsName(String rfsName) {
2582:
2583:                if (rfsName != null) {
2584:                    // default case
2585:                    if (rfsName.startsWith(m_rfsPrefix + "/")) {
2586:                        return true;
2587:                    }
2588:                    // additional rules
2589:                    Iterator it = m_rfsRules.iterator();
2590:                    while (it.hasNext()) {
2591:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
2592:                                .next();
2593:                        String rfsPrefix = rule.getRfsPrefix() + "/";
2594:                        if (rfsName.startsWith(rfsPrefix)) {
2595:                            return true;
2596:                        }
2597:                    }
2598:                }
2599:                return false;
2600:            }
2601:
2602:            /**
2603:             * Checks if a String is a valid URL.<p>
2604:             * 
2605:             * @param inputString The String to check can be <code>null</code>
2606:             * 
2607:             * @return <code>true</code> if the String is not <code>null</code> and a valid URL
2608:             */
2609:            protected boolean isValidURL(String inputString) {
2610:
2611:                boolean isValid = false;
2612:                try {
2613:                    if (inputString != null) {
2614:                        URL tempURL = new URL(inputString);
2615:                        isValid = (tempURL.getProtocol() != null);
2616:                    }
2617:                } catch (MalformedURLException mue) {
2618:                    // ignore because it is not harmful
2619:                }
2620:                return isValid;
2621:            }
2622:
2623:            /**
2624:             * Returns a normalized export path.<p>
2625:             * 
2626:             * Replacing macros, normalizing the path and taking care of relative paths.<p>
2627:             * 
2628:             * @param exportPath the export path to normalize
2629:             * 
2630:             * @return the normalized export path
2631:             */
2632:            protected String normalizeExportPath(String exportPath) {
2633:
2634:                String result = insertContextStrings(exportPath);
2635:                result = OpenCms.getSystemInfo()
2636:                        .getAbsoluteRfsPathRelativeToWebApplication(result);
2637:                if (result.endsWith(File.separator)) {
2638:                    // ensure export path does NOT end with a File.separator
2639:                    result = result.substring(0, result.length() - 1);
2640:                }
2641:                return result;
2642:            }
2643:
2644:            /**
2645:             * Returns a normalized rfs prefix.<p>
2646:             * 
2647:             * Replacing macros and normalizing the path.<p>
2648:             * 
2649:             * @param rfsPrefix the prefix to normalize
2650:             * 
2651:             * @return the normalized rfs prefix
2652:             */
2653:            protected String normalizeRfsPrefix(String rfsPrefix) {
2654:
2655:                String result = insertContextStrings(rfsPrefix);
2656:                if (!isValidURL(result)) {
2657:                    result = CmsFileUtil.normalizePath(result, '/');
2658:                }
2659:                result = CmsFileUtil.normalizePath(result, '/');
2660:                if (CmsResource.isFolder(result)) {
2661:                    // ensure prefix does NOT end with a folder '/'
2662:                    result = result.substring(0, result.length() - 1);
2663:                }
2664:                return result;
2665:            }
2666:
2667:            /**
2668:             * Scrubs all the "export" folders.<p>
2669:             * 
2670:             * @param report an I_CmsReport instance to print output message, or null to write messages to the log file   
2671:             */
2672:            protected void scrubExportFolders(I_CmsReport report) {
2673:
2674:                if (report != null) {
2675:                    report.println(Messages.get().container(
2676:                            Messages.RPT_DELETING_EXPORT_FOLDERS_BEGIN_0),
2677:                            I_CmsReport.FORMAT_HEADLINE);
2678:                }
2679:                synchronized (m_lockScrubExportFolders) {
2680:                    int count = 0;
2681:                    Integer size = new Integer(m_rfsRules.size() + 1);
2682:                    // default case
2683:                    String exportFolderName = CmsFileUtil
2684:                            .normalizePath(m_staticExportPath + '/');
2685:                    try {
2686:                        File exportFolder = new File(exportFolderName);
2687:                        // check if export file exists, if so delete it
2688:                        if (exportFolder.exists() && exportFolder.canWrite()) {
2689:                            CmsFileUtil.purgeDirectory(exportFolder);
2690:                        }
2691:                        count++;
2692:                        if (report != null) {
2693:                            report
2694:                                    .println(
2695:                                            Messages
2696:                                                    .get()
2697:                                                    .container(
2698:                                                            Messages.RPT_DELETE_EXPORT_FOLDER_3,
2699:                                                            new Integer(count),
2700:                                                            size,
2701:                                                            exportFolderName),
2702:                                            I_CmsReport.FORMAT_NOTE);
2703:                        } else {
2704:                            // write log message
2705:                            if (LOG.isInfoEnabled()) {
2706:                                LOG.info(Messages.get().getBundle().key(
2707:                                        Messages.LOG_DEL_MAIN_SE_FOLDER_1,
2708:                                        exportFolderName));
2709:                            }
2710:                        }
2711:                    } catch (Throwable t) {
2712:                        // ignore, nothing to do about the
2713:                        if (LOG.isWarnEnabled()) {
2714:                            LOG.warn(Messages.get().getBundle().key(
2715:                                    Messages.LOG_FOLDER_DELETION_FAILED_1,
2716:                                    exportFolderName), t);
2717:                        }
2718:                    }
2719:                    // iterate over the rules
2720:                    Iterator it = m_rfsRules.iterator();
2721:                    while (it.hasNext()) {
2722:                        CmsStaticExportRfsRule rule = (CmsStaticExportRfsRule) it
2723:                                .next();
2724:                        exportFolderName = CmsFileUtil.normalizePath(rule
2725:                                .getExportPath() + '/');
2726:                        try {
2727:                            File exportFolder = new File(exportFolderName);
2728:                            // check if export file exists, if so delete it
2729:                            if (exportFolder.exists()
2730:                                    && exportFolder.canWrite()) {
2731:                                CmsFileUtil.purgeDirectory(exportFolder);
2732:                            }
2733:                            count++;
2734:                            if (report != null) {
2735:                                report.println(Messages.get().container(
2736:                                        Messages.RPT_DELETE_EXPORT_FOLDER_3,
2737:                                        new Integer(count), size,
2738:                                        exportFolderName),
2739:                                        I_CmsReport.FORMAT_NOTE);
2740:                            } else {
2741:                                // write log message
2742:                                if (LOG.isInfoEnabled()) {
2743:                                    LOG.info(Messages.get().getBundle().key(
2744:                                            Messages.LOG_DEL_MAIN_SE_FOLDER_1,
2745:                                            exportFolderName));
2746:                                }
2747:                            }
2748:                        } catch (Throwable t) {
2749:                            // ignore, nothing to do about the
2750:                            if (LOG.isWarnEnabled()) {
2751:                                LOG.warn(Messages.get().getBundle().key(
2752:                                        Messages.LOG_FOLDER_DELETION_FAILED_1,
2753:                                        exportFolderName), t);
2754:                            }
2755:                        }
2756:                    }
2757:                }
2758:                if (report != null) {
2759:                    report.println(Messages.get().container(
2760:                            Messages.RPT_DELETING_EXPORT_FOLDERS_END_0),
2761:                            I_CmsReport.FORMAT_HEADLINE);
2762:                }
2763:            }
2764:
2765:            /**
2766:             * Set the list of all resources that have the "exportname" property set.<p>
2767:             */
2768:            protected void setExportnames() {
2769:
2770:                if (LOG.isDebugEnabled()) {
2771:                    LOG.debug(Messages.get().getBundle().key(
2772:                            Messages.LOG_UPDATE_EXPORTNAME_PROP_START_0));
2773:                }
2774:
2775:                List resources;
2776:                CmsObject cms = null;
2777:                try {
2778:                    cms = OpenCms.initCmsObject(OpenCms.getDefaultUsers()
2779:                            .getUserExport());
2780:                    resources = cms
2781:                            .readResourcesWithProperty(CmsPropertyDefinition.PROPERTY_EXPORTNAME);
2782:
2783:                    synchronized (m_lockSetExportnames) {
2784:                        m_exportnameResources = new HashMap(resources.size());
2785:                        for (int i = 0, n = resources.size(); i < n; i++) {
2786:                            CmsResource res = (CmsResource) resources.get(i);
2787:                            try {
2788:                                String foldername = cms.getSitePath(res);
2789:                                String exportname = cms
2790:                                        .readPropertyObject(
2791:                                                foldername,
2792:                                                CmsPropertyDefinition.PROPERTY_EXPORTNAME,
2793:                                                false).getValue();
2794:                                if (exportname != null) {
2795:                                    if (exportname
2796:                                            .charAt(exportname.length() - 1) != '/') {
2797:                                        exportname = exportname + "/";
2798:                                    }
2799:                                    if (exportname.charAt(0) != '/') {
2800:                                        exportname = "/" + exportname;
2801:                                    }
2802:                                    m_exportnameResources.put(exportname,
2803:                                            foldername);
2804:                                }
2805:                            } catch (CmsException e) {
2806:                                // ignore, folder will not be added
2807:                            }
2808:                        }
2809:                        m_exportnameResources = Collections
2810:                                .unmodifiableMap(m_exportnameResources);
2811:                    }
2812:                } catch (CmsException e) {
2813:                    // ignore, no resources will be added at all
2814:                }
2815:                if (LOG.isDebugEnabled()) {
2816:                    LOG.debug(Messages.get().getBundle().key(
2817:                            Messages.LOG_UPDATE_EXPORTNAME_PROP_FINISHED_0));
2818:                }
2819:            }
2820:
2821:            /**
2822:             * Writes a resource to the given export path with the given rfs name and the given content.<p>
2823:             * 
2824:             * @param req the current request
2825:             * @param exportPath the path to export the resource
2826:             * @param rfsName the rfs name
2827:             * @param resource the resource
2828:             * @param content the content
2829:             * 
2830:             * @throws CmsException if something goes wrong
2831:             */
2832:            protected void writeResource(HttpServletRequest req,
2833:                    String exportPath, String rfsName, CmsResource resource,
2834:                    byte[] content) throws CmsException {
2835:
2836:                String exportFileName = CmsFileUtil.normalizePath(exportPath
2837:                        + rfsName);
2838:
2839:                // make sure all required parent folder exist
2840:                createExportFolder(exportPath, rfsName);
2841:                // generate export file instance and output stream
2842:                File exportFile = new File(exportFileName);
2843:                // write new exported file content
2844:                try {
2845:                    FileOutputStream exportStream = new FileOutputStream(
2846:                            exportFile);
2847:                    exportStream.write(content);
2848:                    exportStream.close();
2849:
2850:                    // log export success 
2851:                    if (LOG.isInfoEnabled()) {
2852:                        LOG.info(Messages.get().getBundle().key(
2853:                                Messages.LOG_STATIC_EXPORTED_2,
2854:                                resource.getRootPath(), exportFileName));
2855:                    }
2856:
2857:                } catch (Throwable t) {
2858:                    throw new CmsStaticExportException(Messages.get()
2859:                            .container(Messages.ERR_OUTPUT_STREAM_1,
2860:                                    exportFileName), t);
2861:                }
2862:                // update the file with the modification date from the server
2863:                if (req != null) {
2864:                    Long dateLastModified = (Long) req
2865:                            .getAttribute(CmsRequestUtil.HEADER_OPENCMS_EXPORT);
2866:                    if ((dateLastModified != null)
2867:                            && (dateLastModified.longValue() != -1)) {
2868:                        exportFile.setLastModified((dateLastModified
2869:                                .longValue() / 1000) * 1000);
2870:                        if (LOG.isDebugEnabled()) {
2871:                            LOG
2872:                                    .debug(Messages
2873:                                            .get()
2874:                                            .getBundle()
2875:                                            .key(
2876:                                                    Messages.LOG_SET_LAST_MODIFIED_2,
2877:                                                    exportFile.getName(),
2878:                                                    new Long(
2879:                                                            (dateLastModified
2880:                                                                    .longValue() / 1000) * 1000)));
2881:                        }
2882:                    }
2883:                } else {
2884:                    // otherwise take the last modification date form the OpenCms resource
2885:                    exportFile
2886:                            .setLastModified((resource.getDateLastModified() / 1000) * 1000);
2887:                }
2888:            }
2889:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.