001: /*
002: * MeshCMS - A simple CMS based on SiteMesh
003: * Copyright (C) 2004-2005 Luciano Vernaschi
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * as published by the Free Software Foundation; either version 2
008: * of the License, or (at your option) any later version.
009: *
010: * This program is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU General Public License for more details.
014: *
015: * You should have received a copy of the GNU General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: *
019: * You can contact the author at http://www.cromoteca.com
020: * and at info@cromoteca.com
021: */
022:
023: package org.meshcms.extra;
024:
025: import java.io.*;
026: import java.net.*;
027: import javax.servlet.http.*;
028: import org.meshcms.core.*;
029: import org.meshcms.util.*;
030:
031: /**
032: * Performs the export of a website in static files (for use with the Apache
033: * web server or any other one).
034: */
035: public class StaticExporter extends DirectoryParser {
036: public static final String REQUEST_ATTRIBUTE_CHECK = "meshcms-is-exporting";
037: public static final String USER_AGENT_HEADER = "User-Agent";
038:
039: public static final String USER_AGENT = WebSite.APP_NAME + ' '
040: + WebSite.VERSION_ID + " ("
041: + System.getProperty("java.version") + ' '
042: + System.getProperty("java.vendor") + ", "
043: + System.getProperty("os.name") + ' '
044: + System.getProperty("os.version") + ' '
045: + System.getProperty("os.arch") + ')';
046:
047: File staticDir;
048: URL contextURL;
049: boolean checkDates = true;
050: Writer writer;
051: WebSite webSite;
052:
053: /**
054: * Creates an instance.
055: *
056: * @param staticDir the directory where files should be exported
057: */
058: public StaticExporter(WebSite webSite, URL contextURL,
059: File staticDir) {
060: super ();
061: setProcessStartDir(true);
062: setRecursive(true);
063: setInitialDir(webSite.getRootFile());
064: setStaticDir(staticDir);
065: this .webSite = webSite;
066: this .contextURL = contextURL;
067: }
068:
069: /**
070: * Sets the static directory.
071: */
072: public void setStaticDir(File staticDir) {
073: this .staticDir = staticDir;
074: }
075:
076: /**
077: * Returns the static directory.
078: */
079: public File getStaticDir() {
080: return staticDir;
081: }
082:
083: /**
084: * Sets the context URL.
085: */
086: public void setContextURL(URL contextURL) {
087: this .contextURL = contextURL;
088: }
089:
090: /**
091: * Returns the context URL.
092: */
093: public URL getContextURL() {
094: return contextURL;
095: }
096:
097: /**
098: * Sets the date check to on or off. If the date check is on, only newer
099: * files are copied. HTML are always recreated regardless of this option.
100: * Default is true (recommended).
101: */
102: public void setCheckDates(boolean checkDates) {
103: this .checkDates = checkDates;
104: }
105:
106: /**
107: * Returns the value of the date check option.
108: */
109: public boolean getCheckDates() {
110: return checkDates;
111: }
112:
113: /**
114: * Sets the writer for logging (usually the writer of the web page).
115: */
116: public void setWriter(Writer writer) {
117: this .writer = writer;
118: }
119:
120: /**
121: * Returns the writer (if any).
122: */
123: public Writer getWriter() {
124: return writer;
125: }
126:
127: protected void postProcess() {
128: MainWebSite mainWebSite = null;
129:
130: if (webSite instanceof VirtualWebSite) {
131: mainWebSite = ((VirtualWebSite) webSite).getMainWebSite();
132: }
133:
134: write("");
135: StaticExportCopier copier = new StaticExportCopier(staticDir);
136: copier.setInitialDir(initialDir);
137: copier.setWriter(writer);
138: copier.setCheckDates(checkDates);
139: copier.process();
140:
141: write("");
142: StaticExportCleaner cleaner = new StaticExportCleaner(
143: initialDir);
144: cleaner.setInitialDir(staticDir);
145: cleaner.setWriter(writer);
146:
147: if (mainWebSite != null) {
148: cleaner.setProtectedPath(webSite.getAdminPath());
149: }
150:
151: cleaner.process();
152:
153: if (mainWebSite != null) {
154: File adminStaticDir = webSite.getAdminPath().getFile(
155: staticDir);
156: File adminDir = mainWebSite.getFile(mainWebSite
157: .getAdminPath());
158:
159: write("");
160: StaticExportCopier adminCopier = new StaticExportCopier(
161: adminStaticDir);
162: adminCopier.setMkDirs(true);
163: adminCopier.setInitialDir(adminDir);
164: adminCopier.setWriter(writer);
165: adminCopier.setCheckDates(checkDates);
166: adminCopier.process();
167:
168: write("");
169: StaticExportCleaner adminCleaner = new StaticExportCleaner(
170: adminDir);
171: adminCleaner.setInitialDir(adminStaticDir);
172: adminCleaner.setWriter(writer);
173: adminCleaner.process();
174: }
175: }
176:
177: protected boolean preProcessDirectory(File file, Path path) {
178: File dir = path.getFile(staticDir);
179:
180: if (isExportable(path)) {
181: dir.mkdirs();
182: } else {
183: new DirectoryRemover(dir).process();
184: }
185:
186: return dir.isDirectory();
187: }
188:
189: protected void processFile(File file, Path path) {
190: File staticFile = path.getFile(staticDir);
191: String fileName = file.getName();
192:
193: try {
194: if (FileTypes.isPage(fileName)) {
195: long time = System.currentTimeMillis();
196: URL url = new URL(contextURL, path.toString());
197: HttpURLConnection connection = (HttpURLConnection) url
198: .openConnection();
199: connection.setRequestProperty(USER_AGENT_HEADER,
200: USER_AGENT);
201: InputStream in = connection.getInputStream();
202: OutputStream out = new FileOutputStream(staticFile);
203: Utils.copyStream(in, out, true);
204: connection.disconnect();
205: write(path + " page generated in "
206: + (System.currentTimeMillis() - time) + " ms");
207: }
208: } catch (IOException ex) {
209: ex.printStackTrace();
210: }
211: }
212:
213: void write(String message) {
214: if (writer != null) {
215: try {
216: writer.write(message);
217: writer.write('\n');
218: writer.flush();
219: } catch (IOException ex) {
220: }
221: }
222: }
223:
224: public boolean isExportable(Path path) {
225: if (path == null || path.isRelative()) {
226: return false;
227: }
228:
229: if (path.isRoot()) {
230: return true;
231: }
232:
233: if (webSite.getAdminPath() == null
234: || !(path.equals(webSite.getPrivatePath()) || path
235: .equals(webSite.getVirtualSitesPath()))) {
236: String level1 = path.getElementAt(0).toLowerCase();
237: return !(level1.equals("web-inf") || level1
238: .equals("meta-inf"));
239: }
240:
241: return false;
242: }
243:
244: public void process() {
245: // Avoid to store generated pages in cache
246: Configuration conf = webSite.getConfiguration();
247: int cacheType = conf.getCacheType();
248: conf.setCacheType(Configuration.NO_CACHE);
249:
250: write("base url: " + contextURL);
251:
252: // Update the site map to make sure everything is up to date
253: long time = System.currentTimeMillis();
254: webSite.updateSiteMap(true);
255: write("site map updated in "
256: + (System.currentTimeMillis() - time) + " ms");
257:
258: write("");
259: super .process();
260:
261: // Restore cache
262: conf.setCacheType(cacheType);
263: }
264:
265: public static boolean isExportRequest(HttpServletRequest request) {
266: // return USER_AGENT.equals(request.getHeader("User-Agent"));
267: Boolean bo = (Boolean) request
268: .getAttribute(REQUEST_ATTRIBUTE_CHECK);
269:
270: if (bo == null) {
271: String ua = Utils.noNull(request
272: .getHeader(USER_AGENT_HEADER));
273: bo = Boolean.valueOf(ua.startsWith(WebSite.APP_NAME));
274: request.setAttribute(REQUEST_ATTRIBUTE_CHECK, bo);
275: }
276:
277: return bo.booleanValue();
278: }
279: }
|