001: /**
002: * Copyright (c) 2003-2007, David A. Czarnecki
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * Redistributions of source code must retain the above copyright notice, this list of conditions and the
009: * following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
011: * following disclaimer in the documentation and/or other materials provided with the distribution.
012: * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
013: * endorse or promote products derived from this software without specific prior written permission.
014: * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
015: * without prior written permission of David A. Czarnecki.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
018: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
019: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
021: * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
022: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
025: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
029: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030: */package org.blojsom.plugin.admin;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.blojsom.blog.Blog;
035: import org.blojsom.blog.Entry;
036: import org.blojsom.event.EventBroadcaster;
037: import org.blojsom.plugin.PluginException;
038: import org.blojsom.plugin.admin.event.ProcessRequestEvent;
039: import org.blojsom.util.BlojsomConstants;
040: import org.blojsom.util.BlojsomUtils;
041: import org.blojsom.fetcher.Fetcher;
042: import org.blojsom.fetcher.FetcherException;
043:
044: import javax.servlet.http.HttpServletRequest;
045: import javax.servlet.http.HttpServletResponse;
046: import java.io.File;
047: import java.io.IOException;
048: import java.util.*;
049:
050: /**
051: * ThemeSwitcherPlugin
052: *
053: * @author David Czarnecki
054: * @version $Id: ThemeSwitcherPlugin.java,v 1.3 2007/01/17 02:35:05 czarneckid Exp $
055: * @since blojsom 3.0
056: */
057: public class ThemeSwitcherPlugin extends WebAdminPlugin {
058:
059: private Log _logger = LogFactory.getLog(ThemeSwitcherPlugin.class);
060:
061: // Localization constants
062: private static final String FAILED_PERMISSION_KEY = "failed.theme.switch.permission.text";
063: private static final String NONE_SELECTED_KEY = "no.theme.flavor.selected.text";
064: private static final String ADMIN_FLAVOR_PROTECTED_KEY = "admin.flavor.protected.text";
065: private static final String FAILED_THEME_TEMPLATE_COPY_KEY = "failed.theme.template.copy.text";
066: private static final String FAILED_FLAVOR_WRITE_KEY = "failed.flavor.write.text";
067: private static final String THEME_SWITCHED_KEY = "theme.switched.text";
068:
069: // Pages
070: private static final String THEME_SWITCHER_SETTINGS_PAGE = "/org/blojsom/plugin/admin/templates/admin-theme-switcher-settings";
071:
072: // Context variables
073: private static final String THEME_SWITCHER_PLUGIN_AVAILABLE_THEMES = "THEME_SWITCHER_PLUGIN_AVAILABLE_THEMES";
074: private static final String THEME_SWITCHER_PLUGIN_FLAVORS = "THEME_SWITCHER_PLUGIN_FLAVORS";
075: private static final String THEME_SWITCHER_PLUGIN_DEFAULT_FLAVOR = "THEME_SWITCHER_PLUGIN_DEFAULT_FLAVOR";
076: private static final String CURRENT_HTML_THEME = "CURRENT_HTML_THEME";
077:
078: // Actions
079: private static final String SWITCH_THEME_ACTION = "switch-theme";
080:
081: // Form items
082: private static final String THEME = "theme";
083: private static final String FLAVOR = "flavor-name";
084:
085: // Permissions
086: private static final String SWITCH_THEME_PERMISSION = "switch_theme_permission";
087: private static final String DEFAULT_THEMES_DIRECTORY = "/themes/";
088: private static final String THEMES_DIRECTORY_IP = "themes-directory";
089:
090: private String _themesDirectory;
091: private Properties _blojsomProperties;
092: private Fetcher _fetcher;
093: private EventBroadcaster _eventBroadcaster;
094:
095: /**
096: * Default constructor
097: */
098: public ThemeSwitcherPlugin() {
099: }
100:
101: /**
102: * Set the {@link EventBroadcaster}
103: *
104: * @param eventBroadcaster {@link EventBroadcaster}
105: */
106: public void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
107: _eventBroadcaster = eventBroadcaster;
108: }
109:
110: /**
111: * Set the {@link Fetcher}
112: *
113: * @param fetcher {@link Fetcher}
114: */
115: public void setFetcher(Fetcher fetcher) {
116: _fetcher = fetcher;
117: }
118:
119: /**
120: * Set the default blojsom properties
121: *
122: * @param blojsomProperties Default blojsom properties
123: */
124: public void setBlojsomProperties(Properties blojsomProperties) {
125: _blojsomProperties = blojsomProperties;
126: }
127:
128: /**
129: * Initialize this plugin. This method only called when the plugin is instantiated.
130: *
131: * @throws org.blojsom.plugin.PluginException
132: * If there is an error initializing the plugin
133: */
134: public void init() throws PluginException {
135: super .init();
136:
137: _themesDirectory = _blojsomProperties
138: .getProperty(THEMES_DIRECTORY_IP);
139: if (BlojsomUtils.checkNullOrBlank(_themesDirectory)) {
140: _themesDirectory = DEFAULT_THEMES_DIRECTORY;
141: }
142:
143: _themesDirectory = BlojsomUtils
144: .checkStartingAndEndingSlash(_themesDirectory);
145: }
146:
147: /**
148: * Return the display name for the plugin
149: *
150: * @return Display name for the plugin
151: */
152: public String getDisplayName() {
153: return "Theme Switcher plugin";
154: }
155:
156: /**
157: * Return the name of the initial editing page for the plugin
158: *
159: * @return Name of the initial editing page for the plugin
160: */
161: public String getInitialPage() {
162: return THEME_SWITCHER_SETTINGS_PAGE;
163: }
164:
165: /**
166: * Retrieve the list of directories (theme names) from the themes installation directory
167: *
168: * @return List of theme names available
169: */
170: protected String[] getAvailableThemes() {
171: ArrayList themes = new ArrayList(0);
172:
173: File themesDirectory = new File(_servletConfig
174: .getServletContext().getRealPath("/")
175: + BlojsomConstants.DEFAULT_CONFIGURATION_BASE_DIRECTORY
176: + _themesDirectory);
177:
178: if (themesDirectory.exists() && themesDirectory.isDirectory()) {
179: File[] themesInstalled = themesDirectory
180: .listFiles(BlojsomUtils.getDirectoryFilter());
181: if (themesInstalled != null && themesInstalled.length > 0) {
182: for (int i = 0; i < themesInstalled.length; i++) {
183: File installedTheme = themesInstalled[i];
184: themes.add(installedTheme.getName());
185: }
186: }
187: }
188:
189: String[] availableThemes = (String[]) themes
190: .toArray(new String[themes.size()]);
191: Arrays.sort(availableThemes);
192:
193: return availableThemes;
194: }
195:
196: /**
197: * Process the blog entries
198: *
199: * @param httpServletRequest Request
200: * @param httpServletResponse Response
201: * @param blog {@link Blog} instance
202: * @param context Context
203: * @param entries Blog entries retrieved for the particular request
204: * @return Modified set of blog entries
205: * @throws org.blojsom.plugin.PluginException
206: * If there is an error processing the blog entries
207: */
208: public Entry[] process(HttpServletRequest httpServletRequest,
209: HttpServletResponse httpServletResponse, Blog blog,
210: Map context, Entry[] entries) throws PluginException {
211: entries = super .process(httpServletRequest,
212: httpServletResponse, blog, context, entries);
213: String page = BlojsomUtils.getRequestValue(
214: BlojsomConstants.PAGE_PARAM, httpServletRequest);
215:
216: String username = getUsernameFromSession(httpServletRequest,
217: blog);
218: if (!checkPermission(blog, null, username,
219: SWITCH_THEME_PERMISSION)) {
220: httpServletRequest.setAttribute(
221: BlojsomConstants.PAGE_PARAM,
222: ADMIN_ADMINISTRATION_PAGE);
223: addOperationResultMessage(context, getAdminResource(
224: FAILED_PERMISSION_KEY, FAILED_PERMISSION_KEY, blog
225: .getBlogAdministrationLocale()));
226:
227: return entries;
228: }
229:
230: if (ADMIN_LOGIN_PAGE.equals(page)) {
231: return entries;
232: } else {
233: String action = BlojsomUtils.getRequestValue(ACTION_PARAM,
234: httpServletRequest);
235:
236: context.put(THEME_SWITCHER_PLUGIN_AVAILABLE_THEMES,
237: getAvailableThemes());
238: context.put(THEME_SWITCHER_PLUGIN_FLAVORS, new TreeMap(blog
239: .getTemplates()));
240: context.put(THEME_SWITCHER_PLUGIN_DEFAULT_FLAVOR, blog
241: .getBlogDefaultFlavor());
242: String currentHtmlFlavor = (String) blog.getTemplates()
243: .get(BlojsomConstants.DEFAULT_FLAVOR_HTML);
244: currentHtmlFlavor = currentHtmlFlavor.substring(0,
245: currentHtmlFlavor.indexOf('.'));
246: context.put(CURRENT_HTML_THEME, currentHtmlFlavor);
247:
248: if (SWITCH_THEME_ACTION.equals(action)) {
249: String theme = BlojsomUtils.getRequestValue(THEME,
250: httpServletRequest);
251: String flavor = BlojsomUtils.getRequestValue(FLAVOR,
252: httpServletRequest);
253:
254: if (BlojsomUtils.checkNullOrBlank(theme)
255: || BlojsomUtils.checkNullOrBlank(flavor)) {
256: addOperationResultMessage(context,
257: getAdminResource(NONE_SELECTED_KEY,
258: NONE_SELECTED_KEY,
259: blog.getBlogAdministrationLocale()));
260: return entries;
261: }
262:
263: if ("admin".equalsIgnoreCase(flavor)) {
264: addOperationResultMessage(context,
265: getAdminResource(
266: ADMIN_FLAVOR_PROTECTED_KEY,
267: ADMIN_FLAVOR_PROTECTED_KEY,
268: blog.getBlogAdministrationLocale()));
269: return entries;
270: }
271:
272: File copyFromTemplatesDirectory = new File(
273: _servletConfig.getServletContext().getRealPath(
274: "/")
275: + BlojsomConstants.DEFAULT_CONFIGURATION_BASE_DIRECTORY
276: + _themesDirectory
277: + theme
278: + "/"
279: + _blojsomProperties
280: .getProperty(BlojsomConstants.TEMPLATES_DIRECTORY_IP));
281:
282: File[] templateFiles = copyFromTemplatesDirectory
283: .listFiles();
284: String mainTemplate = null;
285:
286: if (templateFiles != null && templateFiles.length > 0) {
287: for (int i = 0; i < templateFiles.length; i++) {
288: File templateFile = templateFiles[i];
289: if (!templateFile.isDirectory()) {
290: if (templateFile.getName().startsWith(
291: theme + ".")) {
292: mainTemplate = templateFile.getName();
293: }
294: }
295: }
296: }
297:
298: File copyToTemplatesDirectory = new File(
299: _servletConfig.getServletContext().getRealPath(
300: "/")
301: + BlojsomConstants.DEFAULT_CONFIGURATION_BASE_DIRECTORY
302: + _blojsomProperties
303: .getProperty(BlojsomConstants.BLOGS_DIRECTORY_IP)
304: + blog.getBlogId()
305: + "/"
306: + _blojsomProperties
307: .getProperty(BlojsomConstants.TEMPLATES_DIRECTORY_IP));
308:
309: try {
310: BlojsomUtils.copyDirectory(
311: copyFromTemplatesDirectory,
312: copyToTemplatesDirectory);
313: } catch (IOException e) {
314: _logger.error(e);
315: addOperationResultMessage(context,
316: getAdminResource(
317: FAILED_THEME_TEMPLATE_COPY_KEY,
318: FAILED_THEME_TEMPLATE_COPY_KEY,
319: blog.getBlogAdministrationLocale()));
320: }
321:
322: File copyFromResourcesDirectory = new File(
323: _servletConfig.getServletContext().getRealPath(
324: "/")
325: + BlojsomConstants.DEFAULT_CONFIGURATION_BASE_DIRECTORY
326: + _themesDirectory
327: + theme
328: + "/"
329: + _blojsomProperties
330: .getProperty(BlojsomConstants.RESOURCES_DIRECTORY_IP));
331: File copyToResourcesDirectory = new File(
332: _servletConfig.getServletContext().getRealPath(
333: "/")
334: + _blojsomProperties
335: .getProperty(BlojsomConstants.RESOURCES_DIRECTORY_IP)
336: + blog.getBlogId() + "/");
337:
338: try {
339: BlojsomUtils.copyDirectory(
340: copyFromResourcesDirectory,
341: copyToResourcesDirectory);
342: } catch (IOException e) {
343: _logger.error(e);
344: addOperationResultMessage(context,
345: getAdminResource(
346: FAILED_THEME_TEMPLATE_COPY_KEY,
347: FAILED_THEME_TEMPLATE_COPY_KEY,
348: blog.getBlogAdministrationLocale()));
349: }
350:
351: try {
352: if (mainTemplate == null) {
353: mainTemplate = (String) blog.getTemplates()
354: .get(flavor);
355:
356: _logger
357: .debug("No main template supplied for "
358: + theme
359: + " theme. Using existing template for flavor: "
360: + mainTemplate);
361: } else {
362: if (BlojsomConstants.DEFAULT_FLAVOR_HTML
363: .equals(flavor)) {
364: mainTemplate += ", "
365: + "text/html;charset=UTF-8";
366: }
367: }
368:
369: Map templates = new HashMap(blog.getTemplates());
370: templates.put(flavor, mainTemplate);
371: blog.setTemplates(templates);
372:
373: _fetcher.saveBlog(blog);
374: } catch (FetcherException e) {
375: _logger.error(e);
376: addOperationResultMessage(context,
377: getAdminResource(FAILED_FLAVOR_WRITE_KEY,
378: FAILED_FLAVOR_WRITE_KEY,
379: blog.getBlogAdministrationLocale()));
380:
381: return entries;
382: }
383:
384: currentHtmlFlavor = (String) blog.getTemplates().get(
385: BlojsomConstants.DEFAULT_FLAVOR_HTML);
386: currentHtmlFlavor = currentHtmlFlavor.substring(0,
387: currentHtmlFlavor.indexOf('.'));
388: context.put(CURRENT_HTML_THEME, currentHtmlFlavor);
389:
390: addOperationResultMessage(context, formatAdminResource(
391: THEME_SWITCHED_KEY, THEME_SWITCHED_KEY, blog
392: .getBlogAdministrationLocale(),
393: new Object[] { theme, flavor }));
394: _eventBroadcaster.processEvent(new ProcessRequestEvent(
395: this , new Date(), blog, httpServletRequest,
396: httpServletResponse, context));
397: } else {
398: _eventBroadcaster.processEvent(new ProcessRequestEvent(
399: this , new Date(), blog, httpServletRequest,
400: httpServletResponse, context));
401:
402: context.put(THEME_SWITCHER_PLUGIN_AVAILABLE_THEMES,
403: getAvailableThemes());
404: }
405: }
406:
407: return entries;
408: }
409: }
|