KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > meshcms > core > WebSite


1 /*
2  * MeshCMS - A simple CMS based on SiteMesh
3  * Copyright (C) 2004-2007 Luciano Vernaschi
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * You can contact the author at http://www.cromoteca.com
20  * and at info@cromoteca.com
21  */

22
23 package org.meshcms.core;
24
25 import java.io.*;
26 import java.nio.charset.*;
27 import java.util.*;
28 import javax.servlet.*;
29 import javax.servlet.http.*;
30 import org.apache.commons.fileupload.*;
31 import org.meshcms.util.*;
32 import com.thoughtworks.xstream.*;
33 import com.thoughtworks.xstream.io.StreamException;
34 import com.thoughtworks.xstream.io.xml.*;
35
36 public class WebSite {
37   public static final String JavaDoc APP_NAME = "MeshCMS";
38   public static final String JavaDoc VERSION_ID = "3.0.4";
39   public static final String JavaDoc SYSTEM_CHARSET;
40   public static final boolean IS_MULTIBYTE_SYSTEM_CHARSET;
41
42   /**
43    * A prefix to be used for every backup file.
44    */

45   public static final String JavaDoc BACKUP_PREFIX = "_bak_";
46
47   /**
48    * A prefix to be used for every backup dir.
49    */

50   public static final String JavaDoc BACKUP_DIR_PREFIX = "_dirbak_";
51
52   /**
53    * A prefix to be used for every temporary file created in the repository.
54    */

55   public static final String JavaDoc TEMP_PREFIX = "_tmp_";
56
57   /**
58    * Name of the default admin theme folder.
59    */

60   public static final String JavaDoc ADMIN_THEME = "theme";
61
62   public static final String JavaDoc CMS_ID_FILE = "meshcms_id";
63
64   public static final String JavaDoc ADMIN_ID_FILE = "meshcms_admin_id";
65
66   static {
67     String JavaDoc s = System.getProperty("file.encoding", "ISO-8859-1");
68     boolean multibyte = true;
69
70     try {
71       Charset c = Charset.forName(s);
72       s = c.toString();
73       multibyte = c.newEncoder().maxBytesPerChar() > 1.0F;
74     } catch (Exception JavaDoc ex) {}
75
76     SYSTEM_CHARSET = s;
77     IS_MULTIBYTE_SYSTEM_CHARSET = multibyte;
78   }
79
80   protected ServletContext sc;
81   protected String JavaDoc[] welcomeFiles;
82
83   protected File rootFile;
84   protected long lastAdminThemeBlock;
85   protected long statsZero;
86   protected int statsLength;
87   protected Configuration configuration;
88   protected SiteInfo siteInfo;
89   protected SiteMap siteMap;
90   protected Path rootPath;
91
92   protected Path cmsPath;
93   protected Path adminPath;
94   protected Path adminThemePath;
95   protected Path adminModulesPath;
96   protected Path adminThemesPath;
97   protected Path adminScriptsPath;
98   protected Path privatePath;
99   protected Path usersPath;
100   protected Path virtualSitesPath;
101   protected Path repositoryPath;
102   protected Path customModulesPath;
103   protected Path generatedFilesPath;
104   protected Path moduleDataPath;
105   protected Path customThemesPath;
106
107   protected Path configFilePath;
108   protected Path propertiesFilePath;
109   protected Path sitesFilePath;
110
111   protected WebSite() {
112   }
113
114   protected static WebSite create(ServletContext sc,
115       String JavaDoc[] welcomeFiles, File rootFile, Path rootPath, Path cmsPath) {
116     WebSite webSite = new WebSite();
117     webSite.init(sc, welcomeFiles, rootFile, rootPath, cmsPath);
118     return webSite;
119   }
120
121   protected void init(ServletContext sc, String JavaDoc[] welcomeFiles, File rootFile,
122       Path rootPath, Path cmsPath) {
123     this.sc = sc;
124     this.welcomeFiles = welcomeFiles;
125     this.rootFile = rootFile;
126     this.rootPath = rootPath;
127     this.cmsPath = cmsPath;
128
129     // PLEASE NOTE: the initialization order is important.
130
if (cmsPath != null) {
131       adminPath = cmsPath.add("admin");
132       adminThemePath = adminPath.add(ADMIN_THEME);
133       adminModulesPath = adminPath.add("modules");
134       adminThemesPath = adminPath.add("themes");
135       adminScriptsPath = adminPath.add("scripts");
136       privatePath = cmsPath.add("private");
137       createDir(usersPath = privatePath.add("users"));
138       virtualSitesPath = cmsPath.add("sites");
139       createDir(repositoryPath = privatePath.add("repository"));
140       createDir(customModulesPath = cmsPath.add("modules"));
141       createDir(generatedFilesPath = cmsPath.add("generated"));
142       createDir(moduleDataPath = cmsPath.add("moduledata"));
143       createDir(customThemesPath = cmsPath.add("themes"));
144       configFilePath = privatePath.add("configuration.xml");
145       propertiesFilePath = privatePath.add("siteinfo.xml");
146       sitesFilePath = privatePath.add("sites.xml");
147
148       configuration = Configuration.load(this);
149       statsLength = configuration.getStatsLength();
150       siteInfo = SiteInfo.load(this);
151       updateSiteMap(true);
152     }
153   }
154
155   protected ServletContext getServletContext() {
156     return sc;
157   }
158
159   /**
160    * Creates another instance of <code>SiteMap</code>. If <code>force</code>
161    * is true, a new site map is always created and the method
162    * returns after the new site map is completed. If it is false, a new site map
163    * is created only if the current one is too old. In this case, the site map
164    * is created asynchronously and the method returns immediately. The
165    * repository will be cleaned too.
166    *
167    * @param force it to force the SiteMap creation.
168    */

169   public void updateSiteMap(boolean force) {
170     if (force) {
171       new SiteMap(this).process();
172     } else if (System.currentTimeMillis() - siteMap.getLastModified() >
173                configuration.getUpdateIntervalMillis()) {
174         new SiteMap(this).start();
175       new DirectoryCleaner(getFile(repositoryPath),
176           configuration.getBackupLifeMillis()).start();
177       new DirectoryCleaner(getFile(generatedFilesPath),
178           configuration.getBackupLifeMillis()).start();
179     }
180   }
181
182   void setSiteMap(SiteMap siteMap) {
183     this.siteMap = siteMap;
184   }
185
186   /**
187    * Returns the instance of the <code>SiteMap</code> that is currently manage
188    * the site map. Since this object can be replaced with a new one at any
189    * moment, a class that wants to use it should store it in a local variable
190    * and use it for all the operation/method.
191    *
192    * @return the current instance of SiteMap
193    */

194   public SiteMap getSiteMap() {
195     return siteMap;
196   }
197
198   /**
199    * @return the current configuration of the web application.
200    */

201   public Configuration getConfiguration() {
202     return configuration;
203   }
204
205   /**
206    * Sets the <code>SiteInfo</code> object related to this website.
207    *
208    * @param siteInfo the site info for this website
209    */

210   void setSiteInfo(SiteInfo siteInfo) {
211     this.siteInfo = siteInfo;
212   }
213
214   /**
215    * @return the instance of the <code>SiteInfo</code> class that is managing
216    * the site information.
217    *
218    * @see SiteInfo
219    */

220   public SiteInfo getSiteInfo() {
221     return siteInfo;
222   }
223
224   /**
225    * @return the index of the current day in the array of stats included in any
226    * PageInfo instance.
227    */

228   public int getStatsIndex() {
229     long now = System.currentTimeMillis();
230     long days = (now - statsZero) / Configuration.LENGTH_OF_DAY;
231
232     if (days >= statsLength) {
233       statsZero = now;
234       return 0;
235     } else {
236       return (int) days;
237     }
238   }
239
240   /**
241    * @return the length of stats (hit counts) measured in days.
242    */

243   public int getStatsLength() {
244     return statsLength;
245   }
246
247   /**
248    * Creates a new directory.
249    *
250    * @param user the user that requests the creation of the directory
251    * @param dirPath the path of the new directory
252    *
253    * @return true if the directory has been created or already
254    * existed, false otherwise
255    */

256   public boolean createDirectory(UserInfo user, Path dirPath) {
257     File newDir = getFile(dirPath);
258
259     if (newDir.isDirectory()) {
260       return true;
261     }
262
263     return user != null && user.canWrite(this, dirPath) && newDir.mkdir();
264   }
265
266   /**
267    * Creates a new file. If the extension of the file denotes a web page, the
268    * basic template is copied into the file, otherwise an empty file is created.
269    *
270    * @param user the user that requests the file creation
271    * @param filePath the path of the new file
272    *
273    * @return true if the new file has been created or already existed,
274    * false otherwise
275    */

276   public boolean createFile(UserInfo user, Path filePath) {
277     if (user == null || !user.canWrite(this, filePath)) {
278       return false;
279     }
280
281     File newFile = getFile(filePath);
282
283     if (newFile.exists()) {
284       return !newFile.isDirectory();
285     }
286
287     try {
288       if (FileTypes.isPage(filePath.getLastElement())) {
289         if (newFile.exists()) {
290           return false;
291         }
292
293         return saveToFile(user, getHTMLTemplate(null), filePath);
294       } else {
295         return newFile.createNewFile();
296       }
297     } catch (IOException ex) {
298       sc.log("Can't create file " + newFile, ex);
299     }
300
301     return false;
302   }
303
304   /**
305    * Copies a file to another file in the same directory. An existing file won't
306    * be overwritten.
307    *
308    * @param user the user that requests the operation
309    * @param filePath the path of the old file
310    * @param newName the name of the new file
311    *
312    * @return true if the new file has been copied, false otherwise
313    */

314   public boolean copyFile(UserInfo user, Path filePath, String JavaDoc newName) {
315     return copyFile(user, filePath, filePath.getParent().add(newName));
316   }
317
318   /**
319    * Copies a file (or directory) to another file (or directory).
320    * Existing files won't be overwritten.
321    *
322    * @param user the user that requests the operation
323    * @param oldPath the location of the existing file
324    * @param newPath the location of the new copy of the file
325    *
326    * @return true if the new file has been copied, false otherwise
327    */

328   public boolean copyFile(UserInfo user, Path oldPath, Path newPath) {
329     File oldFile = getFile(oldPath);
330
331     if (!oldFile.exists()) {
332       return false;
333     }
334
335     File newFile = getFile(newPath);
336
337     if (user == null || !user.canWrite(this, newPath)) {
338       return false;
339     }
340
341     if (oldFile.isDirectory()) {
342       return Utils.copyDirectory(oldFile, newFile, false, false, false);
343     } else {
344     try {
345       return Utils.copyFile(oldFile, newFile, false, false);
346     } catch (IOException ex) {
347       sc.log("Can't copy file " + oldFile + " to file " + newFile, ex);
348       }
349     }
350
351     return false;
352   }
353
354   /**
355    * Renames a file.
356    *
357    * @param user the user that requests the operation
358    * @param filePath the path of the file
359    * @param newName the name of the new file
360    *
361    * @return true if the new file has been renamed, false otherwise
362    */

363   public boolean rename(UserInfo user, Path filePath, String JavaDoc newName) {
364     return move(user, filePath, filePath.getParent().add(newName));
365   }
366
367   /**
368    * Moves (or renames) a file.
369    *
370    * @param user the user that requests the operation
371    * @param oldPath the current location of the file
372    * @param newPath the new location of the file
373    *
374    * @return true if the new file has been moved, false otherwise
375    */

376   public boolean move(UserInfo user, Path oldPath, Path newPath) {
377     File oldFile = getFile(oldPath);
378
379     if (!oldFile.exists()) {
380       return false;
381     }
382
383     if (newPath.isContainedIn(oldPath)) {
384       return false;
385     }
386
387     if (user == null ||
388         !(user.canWrite(this, oldPath) && user.canWrite(this, newPath))) {
389       return false;
390     }
391
392     File newFile = getFile(newPath);
393
394     if (Utils.forceRenameTo(oldFile, newFile, false)) {
395       return true;
396     } else {
397       sc.log("Can't move file " + oldFile + " to file " + newFile);
398     }
399
400     return false;
401   }
402
403   /**
404    * Deletes a file or directory.
405    *
406    * @deprecated use {@link #delete(UserInfo, Path, boolean)} so you are
407    * explicitly requested to allow deletion of non-empty directories
408    */

409   public boolean delete(UserInfo user, Path filePath) {
410     return delete(user, filePath, true);
411   }
412
413   /**
414    * Deletes a file or directory.
415    *
416    * @param user the user that requests the operation
417    * @param filePath the path of the file
418    * @param deleteNonEmptyDirectories if true, non-empty directories will be
419    * deleted too
420    *
421    * @return true if the file has been deleted, false otherwise
422    */

423   public boolean delete(UserInfo user, Path filePath,
424       boolean deleteNonEmptyDirectories) {
425     if (user == null || !user.canWrite(this, filePath)) {
426       return false;
427     }
428
429     // avoid deletion of mandatory CMS items
430
if (cmsPath.isContainedIn(filePath) ||
431         filePath.isChildOf(cmsPath) ||
432         filePath.isContainedIn(adminPath) ||
433         filePath.isChildOf(privatePath)) {
434       return false;
435     }
436
437     File file = getFile(filePath);
438
439     if (!file.exists()) {
440       return false;
441     }
442
443     if (file.isDirectory()) {
444       /* First try to delete a directory as if it were empty. If not, and if
445          deletion of non-empty directories is allowed, backup and delete with backupDir */

446       return file.delete() ||
447           (deleteNonEmptyDirectories && backupDir(user, filePath));
448     } else {
449       return backupFile(user, filePath);
450     }
451   }
452
453   /**
454    * Sets the last modified date of the file to the current time.
455    *
456    * @param user the user that requests the operation
457    * @param filePath the path of the file
458    *
459    * @return true if the date has been changed, false otherwise
460    */

461   public boolean touch(UserInfo user, Path filePath) {
462     return setFileTime(user, filePath, System.currentTimeMillis());
463   }
464
465   public boolean setFileTime(UserInfo user, Path filePath, long time) {
466     if (user == null || !user.canWrite(this, filePath)) {
467       return false;
468     }
469
470     File file = getFile(filePath);
471
472     if (!file.exists()) {
473       return false;
474     }
475
476     file.setLastModified(time);
477     return true;
478   }
479
480   /**
481    * Stores an object into a file. Supported objects are:
482    *
483    * <ul>
484    * <li>byte arrays</li>
485    * <li>input streams</li>
486    * <li><code>org.apache.commons.fileupload.FileItem</code>
487    * (uploaded files)</li>
488    * <li>generic objects. The <code>toString()</code> method is used in this
489    * cases. This is compatible with many kinds of objects: strings,
490    * string buffers and so on.</li>
491    * </ul>
492    *
493    * @param user the user that requests the operation
494    * @param saveThis the object to be stored in the file
495    * @param filePath the path of the file to be written. If the file exists, it
496    * will be backed up and overwritten
497    *
498    * @return true if the operation has been completed successfully,
499    * false otherwise
500    */

501   public boolean saveToFile(UserInfo user, Object JavaDoc saveThis, Path filePath) {
502     if (user == null || !user.canWrite(this, filePath)) {
503       return false;
504     }
505
506     File file = getFile(filePath);
507     File dir = file.getParentFile();
508     dir.mkdirs();
509     File tempFile = null;
510
511     String JavaDoc fileName = file.getName();
512     int dot = fileName.lastIndexOf('.');
513     String JavaDoc fileExt = (dot == -1) ? ".bak" : fileName.substring(dot);
514
515     if (file.exists()) {
516       tempFile = getRepositoryFile(filePath, TEMP_PREFIX +
517           System.currentTimeMillis() + fileExt);
518     }
519
520     File writeTo = tempFile == null ? file : tempFile;
521
522     if (saveThis instanceof byte[]) {
523       byte[] b = (byte[]) saveThis;
524       FileOutputStream fos = null;
525
526       try {
527         fos = new FileOutputStream(writeTo);
528         fos.write(b);
529       } catch (IOException ex) {
530         sc.log("Can't write byte array to file " + writeTo, ex);
531         return false;
532       } finally {
533         if (fos != null) {
534           try {
535             fos.close();
536           } catch (IOException ex) {
537             sc.log("Can't close file " + writeTo, ex);
538           }
539         }
540       }
541     } else if (saveThis instanceof InputStream) {
542       try {
543         InputStream is = (InputStream) saveThis;
544         Utils.copyStream(is, new FileOutputStream(writeTo), true);
545         is.close();
546       } catch (Exception JavaDoc ex) {
547         sc.log("Can't write stream to file " + writeTo, ex);
548         return false;
549       }
550     } else if (saveThis instanceof FileItem) {
551       try {
552         ((FileItem) saveThis).write(writeTo);
553       } catch (Exception JavaDoc ex) {
554         sc.log("Can't write uploaded file to file " + writeTo, ex);
555         return false;
556       }
557     } else {
558       Writer writer = null;
559
560       try {
561         writer = new BufferedWriter(new FileWriter(writeTo));
562         writer.write(saveThis.toString());
563       } catch (IOException ex) {
564         sc.log("Can't write generic object to file " + writeTo, ex);
565         return false;
566       } finally {
567         if (writer != null) {
568           try {
569             writer.close();
570           } catch (IOException ex) {
571             sc.log("Can't close file " + writeTo, ex);
572           }
573         }
574       }
575     }
576
577     if (tempFile != null) {
578       if (!backupFile(user, filePath)) {
579         return false;
580       }
581
582       if (!Utils.forceRenameTo(tempFile, file, true)) {
583         sc.log("Can't rename temporary file " + tempFile + " to file " + file);
584         return false;
585       }
586     }
587
588     return true;
589   }
590
591   /**
592    * Returns the correct file in the repository. For example, if you need to
593    * create a temporary copy of /somedir/index.html, you could use
594    * <code>filePath = /somedir/index.html</code> and
595    * <code>fileName = tmp.html</code>.
596    *
597    * @param filePath the path where to search
598    * @param fileName the file name
599    *
600    * @return the searched file
601    */

602   public File getRepositoryFile(Path filePath, String JavaDoc fileName) {
603     File repoDir = getFile(repositoryPath.add(filePath));
604     repoDir.mkdirs();
605     return new File(repoDir, fileName);
606   }
607
608   private boolean backupFile(UserInfo user, Path filePath) {
609     /* permissions already checked in methods that call this one
610     if (user == null || !user.canWrite(this, filePath)) {
611       return false;
612     }
613     */

614
615     File file = getFile(filePath);
616     String JavaDoc fileName = file.getName();
617     int dot = fileName.lastIndexOf('.');
618     String JavaDoc fileExt = (dot == -1) ? ".bak" : fileName.substring(dot);
619
620     File bakFile = getRepositoryFile(filePath, BACKUP_PREFIX +
621         user.getUsername() + "_" +
622         WebUtils.numericDateFormatter.format(new Date()) + fileExt);
623
624     if (Utils.forceRenameTo(file, bakFile, true)) {
625       return true;
626     }
627
628     sc.log("Can't backup path " + filePath);
629     return false;
630   }
631
632   private boolean backupDir(UserInfo user, Path dirPath) {
633     /* permissions to be checked by the caller */
634
635     File dir = getFile(dirPath);
636     File bakFile = getRepositoryFile(dirPath, BACKUP_DIR_PREFIX +
637         user.getUsername() + "_" +
638         WebUtils.numericDateFormatter.format(new Date()) + ".zip");
639     OutputStream os;
640
641     try {
642       os = new BufferedOutputStream(new FileOutputStream(bakFile));
643     } catch (FileNotFoundException ex) {
644       sc.log("can't create stream on " + bakFile, ex);
645       return false;
646     }
647
648     new ZipArchiver(dir, os).process();
649
650     try {
651       os.close();
652     } catch (IOException ex) {
653       sc.log("Can't close file " + bakFile, ex);
654       return false;
655     }
656
657     DirectoryRemover dr = new DirectoryRemover(dir);
658     dr.process();
659     return dr.getResult();
660   }
661
662   public File createDir(Path path) {
663     File dir = getFile(path);
664     dir.mkdirs();
665     return dir.isDirectory() ? dir : null;
666   }
667
668   /**
669    * Returns the file object for a given path in the web application. The file
670    * is not checked for existance.
671    *
672    * @param path the path representation of the file
673    *
674    * @return the file object for this path, or null if it's not found
675    */

676   public File getFile(Path path) {
677     return (path == null || path.isRelative()) ? null :
678         new File(rootFile, path.toString());
679   }
680
681   public File getRootFile() {
682     return rootFile;
683   }
684
685   /**
686    * @return the site root path.
687    */

688   public Path getRootPath() {
689     return rootPath;
690   }
691
692   /**
693    * @return the <code>Path</code> of a file in the context.
694    *
695    * @see #getFile
696    */

697   public Path getPath(File file) {
698     return new Path(Utils.getRelativePath(rootFile, file, "/"));
699   }
700
701   public Path getRequestedPath(HttpServletRequest request) {
702     return new Path(request.getServletPath());
703   }
704
705   public Path getServedPath(HttpServletRequest request) {
706     return new Path(request.getServletPath());
707   }
708
709   public Path getServedPath(Path requestedPath) {
710     return requestedPath;
711   }
712
713   /**
714    * Checks if the given path is a directory in the file system.
715    *
716    * @param path the Path to check
717    *
718    * @return true if the path is a directory.
719    */

720   public boolean isDirectory(Path path) {
721     return getFile(path).isDirectory();
722   }
723
724   /**
725    * Returns the directory that contains the given path. This is different from
726    * {@link org.meshcms.util.Path#getParent}, since if the path is known to
727    * be a directory in the web application, the path itself is returned.
728    *
729    * @param path the Path to check
730    *
731    * @return a directory(that contains the given path) as a Path object.
732    */

733   public Path getDirectory(Path path) {
734     // PageInfo pageInfo = getPageInfo(path);
735
// return pageInfo.isDirectory() ? path : pageInfo.getPath().getParent();
736
if (path == null) {
737       return null;
738     }
739
740     if (getFile(path).isDirectory()) {
741       return path;
742     }
743
744     path = path.getParent();
745
746     if (!path.isRelative() && getFile(path).isDirectory()) {
747       return path;
748     }
749
750     return null;
751   }
752
753   /**
754    * Returns an array of links to the given pages. The strings are in the form
755    * <pre>&lt;a HREF="(page link)" [target] [style]&gt;(page title)&lt;/a&gt;</pre>
756    *
757    * @param pages the array of pages
758    * @param contextPath the context path of the web application (used to build
759    * the links)
760    * @param target the target frame for the links. If a value is given, the
761    * <code>target</code> attribute is added to the <code>a</code> tag
762    * @param style the CSS style for the links. If a value is given, the
763    * <code>class</code> attribute is added to the <code>a</code> tag
764    *
765    * @return an array of strings that contain the <code>a</code> tags
766    */

767   public String JavaDoc[] getLinkList(PageInfo[] pages, String JavaDoc contextPath,
768                               String JavaDoc target, String JavaDoc style) {
769     if (pages == null) {
770       return null;
771     }
772
773     String JavaDoc[] links = new String JavaDoc[pages.length];
774     target = Utils.isNullOrEmpty(target) ? "" : " target=\"" + target + "\"";
775     style = Utils.isNullOrEmpty(style) ? "" : " class=\"" + style + "\"";
776
777     for (int i = 0; i < pages.length; i++) {
778       if (pages[i] == null) {
779         links[i] = "...";
780       } else {
781         links[i] = "<a HREF=\"" + contextPath + getLink(pages[i]) +
782           "\"" + target + style + ">" + siteInfo.getPageTitle(pages[i]) + "</a>";
783       }
784     }
785
786     return links;
787   }
788
789   public String JavaDoc getLink(Path path) {
790     return getFile(path).isDirectory() ? path.getAsLink() + '/' : path.getAsLink();
791   }
792
793   public String JavaDoc getLink(PageInfo pageInfo) {
794     return getLink(pageInfo.getPath());
795   }
796
797   /**
798    * Returns an array of menu titles for the given pages.
799    * {@link SiteInfo} is used to get the titles.
800    *
801    * @param pages an array of pages to be processed
802    *
803    * @return the array of titles for the given pages.
804    */

805   public String JavaDoc[] getTitles(PageInfo[] pages) {
806     if (pages == null) {
807       return null;
808     }
809
810     String JavaDoc[] titles = new String JavaDoc[pages.length];
811
812     for (int i = 0; i < pages.length; i++) {
813       titles[i] = siteInfo.getPageTitle(pages[i]);
814     }
815
816     return titles;
817   }
818
819   /**
820    * Determines if the given path is a system directory, or is contained in a
821    * system directory. System directories are:
822    *
823    * <ul>
824    * <li>the WEB-INF directory (/WEB-INF)</li>
825    * <li>the META-INF directory (/META-INF)</li>
826    * <li>the standard CGI-BIN directory (/cgi-bin)</li>
827    * <li>the MeshCMS admin directory (if <code>checkAdmin</code> is true</li>
828    * </ul>
829    *
830    * @param path the given path(directory) to be checked
831    *
832    * @return true if it is a system directory, false otherwise
833    */

834   public boolean isSystem(Path path) {
835     if (path == null || path.isRoot()) {
836       return false;
837     }
838
839     if (path.isRelative()) {
840       return true;
841     }
842
843     if (adminPath != null && (path.isContainedIn(adminPath) ||
844         path.isContainedIn(privatePath) || path.equals(cmsPath.add(CMS_ID_FILE)))) {
845       return true;
846     }
847
848     String JavaDoc level1 = path.getElementAt(0).toLowerCase();
849
850     return level1.equals("web-inf") || level1.equals("meta-inf") ||
851         level1.equals("cgi-bin");
852   }
853
854   /**
855    * @return true if the extension of the path is known to denote a type of
856    * file that can be edited using the wysiwyg editor.
857    */

858   public boolean isVisuallyEditable(Path path) {
859     return Utils.searchString(configuration.getVisualExtensions(),
860         Utils.getExtension(path, false), true) != -1;
861   }
862
863   /**
864    * @return the path of the module file with the given name.
865    */

866   public Path getModulePath(String JavaDoc moduleName) {
867     if (moduleName.endsWith(".jsp")) {
868       // old module names were in the form module_name.jsp
869
moduleName = moduleName.substring(0, moduleName.length() - 4);
870     }
871
872     return (Path) siteMap.getModulesMap().get(moduleName);
873   }
874
875   /**
876    * @return the path of the admin directory.
877    */

878   public Path getAdminPath() {
879     return adminPath;
880   }
881
882   public Path getCMSPath() {
883     return cmsPath;
884   }
885
886   public boolean isVirtual() {
887     return false;
888   }
889
890   /**
891    * Returns the complete tag used by pages in the admin folder. This way those
892    * pages can set to be themed according to the site preferences (i.e. using
893    * a custom theme or the default admin theme).
894    */

895   public String JavaDoc getAdminMetaThemeTag() {
896     Path themePath = getThemePath(adminPath);
897     return "<meta name=\"decorator\" content=\"/" + getServedPath(themePath) +
898         "/" + SiteMap.THEME_DECORATOR + "\" />";
899   }
900
901   public String JavaDoc getDummyMetaThemeTag() {
902     return "<meta name=\"decorator\" content=\"/" + adminPath + "/theme/dummy.jsp\" />";
903   }
904
905   /**
906    * Returns a string containing a basic HTML page.
907    *
908    * @param pageTitle the content of the &lt;title&gt; tag (if null, the title
909    * will be &quot;New Page&quot;)
910    *
911    * @return a basic "empty" HTML page
912    */

913   public String JavaDoc getHTMLTemplate(String JavaDoc pageTitle) throws IOException {
914     String JavaDoc text = Utils.readFully(getFile(getAdminPath().add("template.html")));
915
916     if (pageTitle != null) {
917       int idx = text.indexOf("New Page");
918
919       if (idx >= 0) {
920         text = text.substring(0, idx) + pageTitle + text.substring(idx + 8);
921       }
922     }
923
924     return text;
925   }
926
927   public boolean isInsideModules(Path path) {
928     return path.isContainedIn(customModulesPath) ||
929         path.isContainedIn(adminModulesPath);
930   }
931
932   public boolean isInsideThemes(Path path) {
933     return path.isContainedIn(customThemesPath) ||
934         path.isContainedIn(adminThemesPath);
935   }
936
937   /**
938    * Logs a string by calling <code>ServletContext.log(s)</code>
939    */

940   protected void log(String JavaDoc s) {
941     sc.log(s);
942   }
943
944   /**
945    * Logs an exception by calling
946    * <code>ServletContext.log(message, throwable)</code>
947    */

948   public void log(String JavaDoc message, Throwable JavaDoc throwable) {
949     sc.log(message, throwable);
950   }
951
952   /**
953    * Checks if the file name is one of the welcome files.
954    *
955    * @param fileName the file name to check
956    * @return true if the given file name is known to be a welcome file name.
957    */

958   public boolean isWelcomeFileName(String JavaDoc fileName) {
959     return Utils.searchString(welcomeFiles, fileName, false) != -1;
960   }
961
962   /**
963    * Returns the array of welcome file names.
964    *
965    * @return an array of welcome file names for the current web application.
966    * Values are fetched from the web.xml file.
967    */

968   public String JavaDoc[] getWelcomeFileNames() {
969     return welcomeFiles;
970   }
971
972   /**
973    * Returns the current welcome file path for the given folder. If there is no
974    * welcome file in that folder, this method returns null.
975    *
976    * @param dirPath the folder where to search the welcome file
977    *
978    * @return the welcome file as a Path object of null if not found.
979    */

980   public Path findCurrentWelcome(Path dirPath) {
981     File dirFile = getFile(dirPath);
982
983     if (dirFile.isDirectory()) {
984       for (int i = 0; i < welcomeFiles.length; i++) {
985         Path wPath = dirPath.add(welcomeFiles[i]);
986
987         if (getFile(wPath).exists()) {
988           return wPath;
989         }
990       }
991     }
992
993     return null;
994   }
995
996   public WebSite getWebSite(ServletRequest request) {
997     return this;
998   }
999
1000  public HttpServletRequest wrapRequest(ServletRequest request) {
1001    return (HttpServletRequest) request;
1002  }
1003
1004  public String JavaDoc getTypeDescription() {
1005    return "single web site";
1006  }
1007
1008  public String JavaDoc toString() {
1009    return "Type: " + getTypeDescription() + "; path: /" + rootPath + "; CMS: " +
1010        (cmsPath == null ? "disabled" : "enabled on path /" + cmsPath);
1011  }
1012
1013  public Object JavaDoc loadFromXML(Path path) {
1014    File file = getFile(path);
1015
1016    if (file.exists()) {
1017      InputStream is = null;
1018
1019      try {
1020        is = new BufferedInputStream(new FileInputStream(file));
1021        XStream xStream = new XStream(new DomDriver());
1022        XStreamPathConverter pConv = new XStreamPathConverter();
1023        pConv.setPrependSlash(true);
1024        xStream.registerConverter(pConv);
1025        
1026        try {
1027          return xStream.fromXML(new InputStreamReader(is, "UTF-8"));
1028        } catch (StreamException ex) {
1029          return xStream.fromXML(is);
1030        }
1031      } catch (IOException ex) {
1032        ex.printStackTrace();
1033      } finally {
1034        if (is != null) {
1035          try {
1036            is.close();
1037          } catch (IOException ex) {
1038            sc.log("Can't close file " + file, ex);
1039          }
1040        }
1041      }
1042    }
1043
1044    return null;
1045  }
1046
1047  public boolean storeToXML(Object JavaDoc o, Path path) {
1048    File file = getFile(path);
1049    OutputStreamWriter osw = null;
1050
1051    try {
1052      osw = new OutputStreamWriter
1053          (new BufferedOutputStream(new FileOutputStream(file)), "UTF-8");
1054      XStream xStream = new XStream(new DomDriver());
1055      XStreamPathConverter pConv = new XStreamPathConverter();
1056      pConv.setPrependSlash(true);
1057      xStream.registerConverter(pConv);
1058      xStream.toXML(o, osw);
1059      return true;
1060    } catch (IOException ex) {
1061      ex.printStackTrace();
1062    } finally {
1063      if (osw != null) {
1064        try {
1065          osw.close();
1066        } catch (IOException ex) {
1067          sc.log("Can't close file " + file, ex);
1068        }
1069      }
1070    }
1071
1072    return false;
1073  }
1074
1075  /**
1076   * Returns the path of the theme to be applied to the given path. This depends
1077   * on the stored values and on the option to use the default theme for the
1078   * admin pages. This method returns null if no theme is found.
1079   *
1080   * @param pagePath the path of the page who's theme is searched.
1081   *
1082   * @return the theme of this page as a Path object
1083   */

1084  public Path getThemePath(Path pagePath) {
1085    Path themePath = siteInfo.getThemePath(pagePath);
1086
1087    if (pagePath.isContainedIn(adminPath)) {
1088      if (configuration.isUseAdminTheme() || themePath == null ||
1089          System.currentTimeMillis() - lastAdminThemeBlock < 300000L || // 5 minutes
1090
!getFile(themePath.add(SiteMap.THEME_DECORATOR)).exists()) {
1091        themePath = adminThemePath;
1092      }
1093    }
1094
1095    return themePath;
1096  }
1097
1098  public Path getAdminThemePath() {
1099    return adminThemePath;
1100  }
1101
1102  public Path getAdminModulesPath() {
1103    return adminModulesPath;
1104  }
1105
1106  public Path getModuleDataPath() {
1107    return moduleDataPath;
1108  }
1109
1110  public Path getAdminThemesPath() {
1111    return adminThemesPath;
1112  }
1113
1114  public Path getAdminScriptsPath() {
1115    return adminScriptsPath;
1116  }
1117
1118  public Path getPrivatePath() {
1119    return privatePath;
1120  }
1121
1122  public Path getUsersPath() {
1123    return usersPath;
1124  }
1125
1126  public Path getVirtualSitesPath() {
1127    return virtualSitesPath;
1128  }
1129
1130  public Path getRepositoryPath() {
1131    return repositoryPath;
1132  }
1133
1134  public Path getCustomModulesPath() {
1135    return customModulesPath;
1136  }
1137
1138  public Path getGeneratedFilesPath() {
1139    return generatedFilesPath;
1140  }
1141
1142  public Path getCustomThemesPath() {
1143    return customThemesPath;
1144  }
1145
1146  public Path getConfigFilePath() {
1147    return configFilePath;
1148  }
1149
1150  public Path getPropertiesFilePath() {
1151    return propertiesFilePath;
1152  }
1153
1154  public Path getSitesFilePath() {
1155    return sitesFilePath;
1156  }
1157
1158  public long getLastAdminThemeBlock() {
1159    return lastAdminThemeBlock;
1160  }
1161
1162  public void setLastAdminThemeBlock(long lastAdminThemeBlock) {
1163    this.lastAdminThemeBlock = lastAdminThemeBlock;
1164  }
1165}
1166
Popular Tags