/* * AdminUtils.java * * This work is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This work is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * Copyright (c) 2004-2006 Per Cederberg. All rights reserved. */ package org.liquidsite.app.admin; import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import org.liquidsite.app.servlet.Application; import org.liquidsite.app.servlet.Configuration; import org.liquidsite.app.template.Template; import org.liquidsite.app.template.TemplateException; import org.liquidsite.app.template.TemplateManager; import org.liquidsite.core.content.Content; import org.liquidsite.core.content.ContentException; import org.liquidsite.core.content.ContentManager; import org.liquidsite.core.content.ContentSecurityException; import org.liquidsite.core.content.Domain; import org.liquidsite.core.content.PersistentObject; import org.liquidsite.core.content.User; import org.liquidsite.core.web.Request; import org.liquidsite.util.log.Log; /** * A class containing general utility methods for the administration * application. * * @author Per Cederberg, <per at percederberg dot net> * @version 1.0 */ public class AdminUtils { /** * The class logger. */ private static final Log LOG = new Log(AdminUtils.class); /** * The application used. */ private static Application application = null; /** * The content manager used for administration. */ private static ContentManager manager = null; /** * Returns the application currently used * * @return the application currently used */ public static Application getApplication() { return application; } /** * Sets the application currently used. * * @param application the application to use */ static void setApplication(Application application) { AdminUtils.application = application; } /** * Returns the content manager for administration. * * @return the content manager for administration * * @throws ContentException if no content manager exists */ public static ContentManager getContentManager() throws ContentException { if (manager == null) { throw new ContentException("no content manager set"); } return manager; } /** * Sets the content manager for administration. * * @param manager the content manager for administration */ static void setContentManager(ContentManager manager) { AdminUtils.manager = manager; } /** * Returns the backup directory for the system. * * @return the backup directory, or * null if not readable */ public static File getBackupDir() { Configuration config; String basedir; File dir; config = getApplication().getConfig(); basedir = config.get(Configuration.FILE_DIRECTORY, null); if (basedir == null) { LOG.error("application base file directory not configured"); return null; } dir = new File(basedir, "backup"); try { if (!dir.exists() && !dir.mkdirs()) { LOG.error("couldn't create backup directory: " + dir); return null; } } catch (SecurityException e) { LOG.error("access denied while creating backup directory: " + dir); return null; } return dir; } /** * Returns the statistics directory for a domain. * * @param domain the domain object * * @return the statistics directory, or * null if not configured or readable */ public static File getStatisticsDir(Domain domain) { Configuration config; String dir; File file; config = getApplication().getConfig(); dir = config.get(Configuration.STATS_DIRECTORY, null); if (dir == null) { return null; } file = new File(dir, domain.getName()); if (file.exists() && file.canRead()) { return file; } else { return null; } } /** * Returns a date format for the specified user. * * @param user the user to create a date format for * * @return a date format for the specified user */ public static SimpleDateFormat getDateFormat(User user) { SimpleDateFormat df; df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); df.setCalendar(Calendar.getInstance(user.getTimeZone())); return df; } /** * Formats a date to a printable string. The user timezone will * be used. * * @param user the current user * @param date the date to format * * @return a printable string with the date */ public static String formatDate(User user, Date date) { if (date == null) { return ""; } else { return getDateFormat(user).format(date); } } /** * Parses a date string into a date. The user timezone will be * used. * * @param user the current user * @param str the string containing the date * * @return the date found * * @throws ParseException if the string didn't contain a valid * date */ public static Date parseDate(User user, String str) throws ParseException { Date date; date = getDateFormat(user).parse(str); if (str.equals(formatDate(user, date))) { return date; } else { throw new ParseException("invalid date: " + str, 0); } } /** * Formats a file size to a printable string. * * @param size the file size to format * * @return a printable string with the file size */ public static String formatFileSize(long size) { float value = size; String unit; if (size > 1000000) { value /= 1048576; unit = " MiB"; } else if (size > 2000) { value /= 1024; unit = " KiB"; } else { unit = " Bytes"; } value = Math.round(value * 10) / 10.0f; if (value == (int) value) { return (int) value + unit; } else { return value + unit; } } /** * Returns the JavaScript representation of a date. The user * timezone will be used. * * @param user the user * @param date the date to present, or null * * @return a JavaScript representation of the date */ public static String getScriptDate(User user, Date date) { if (date == null) { return "null"; } else { return getScriptString(formatDate(user, date)); } } /** * Returns the JavaScript representation of a string. This method * will take care of required character escapes. * * @param str the string to present, or null * * @return a JavaScript representation of the string */ public static String getScriptString(String str) { StringBuffer buffer = new StringBuffer(); char chr; if (str == null) { return "null"; } else { buffer.append("'"); for (int i = 0; i < str.length(); i++) { chr = str.charAt(i); if (chr == '\\') { buffer.append("\\\\"); } else if (chr == '\n') { buffer.append("\\n"); } else if (chr == '\r') { buffer.append("\\r"); } else if (chr == '\t') { buffer.append("\\t"); } else if (chr == '\'') { buffer.append("\\'"); } else if (chr == '"') { buffer.append("\\\""); } else if (chr != '<' && 32 <= chr && chr < 127) { buffer.append(chr); } else { buffer.append("\\u"); if (chr <= 0x000F) { buffer.append("000"); } else if (chr <= 0x00FF) { buffer.append("00"); } else if (chr <= 0x0FFF) { buffer.append("0"); } buffer.append(Integer.toHexString(chr).toUpperCase()); } } buffer.append("'"); return buffer.toString(); } } /** * Returns the XML representation of a string. This method will * escape any XML reserved characters. * * @param str the string to transform * * @return an XML representation of the string */ public static String getXmlString(String str) { StringBuffer buffer = new StringBuffer(); char chr; if (str == null) { return ""; } else { for (int i = 0; i < str.length(); i++) { chr = str.charAt(i); if (chr == '<') { buffer.append("<"); } else if (chr == '>') { buffer.append(">"); } else if (chr == '&') { buffer.append("&"); } else if (chr == '"') { buffer.append("""); } else if (32 <= chr && chr < 127) { buffer.append(chr); } else { buffer.append("&#"); buffer.append((int) chr); buffer.append(";"); } } return buffer.toString(); } } /** * Returns an object category name. The category name is used in * various places to identify incoming or outgoing objects. * * @param obj the domain or content object * * @return the category name, or * null if unknown */ public static String getCategory(Object obj) { if (obj instanceof Domain) { return "domain"; } else if (obj instanceof Content) { return getCategory(((Content) obj).getCategory()); } else { return null; } } /** * Returns a content category name. The category name is used in * various places to identify incoming or outgoing objects. * * @param category the content category number * * @return the category name, or * null if unknown */ public static String getCategory(int category) { switch (category) { case Content.SITE_CATEGORY: return "site"; case Content.TRANSLATOR_CATEGORY: return "translator"; case Content.FOLDER_CATEGORY: return "folder"; case Content.PAGE_CATEGORY: return "page"; case Content.FILE_CATEGORY: return "file"; case Content.TEMPLATE_CATEGORY: return "template"; case Content.SECTION_CATEGORY: return "section"; case Content.DOCUMENT_CATEGORY: return "document"; case Content.FORUM_CATEGORY: return "forum"; case Content.TOPIC_CATEGORY: return "topic"; case Content.POST_CATEGORY: return "post"; default: return null; } } /** * Checks is a specified object is online. This method will check * that all parent content objects are also online. For domain * objects or null, this method always returns true. * * @param obj the domain or content object * * @return true if the object and all parents are online, or * false otherwise * * @throws ContentException if the database couldn't be accessed * properly */ public static boolean isOnline(Object obj) throws ContentException { Content content; if (obj instanceof Content) { content = (Content) obj; return content.isOnline() && isOnline(content.getParent()); } else { return true; } } /** * Returns the domain or content referenced by a request. When * returning a content object, the latest revision (including * work revisions) will be returned. * * @param request the request * * @return the domain or content object referenced, or * null if not found * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ public static PersistentObject getReference(Request request) throws ContentException, ContentSecurityException { User user = request.getUser(); String type = request.getParameter("type"); String id = request.getParameter("id"); String message; int value; if (type == null || id == null) { return null; } else if (type.equals("domain")) { return getContentManager().getDomain(user, id); } else { try { value = Integer.parseInt(id); } catch (NumberFormatException e) { message = "invalid content id: " + id; throw new ContentSecurityException(message); } return getContentManager().getContent(user, value); } } /** * Sets the domain or content reference attributes in a request. * * @param request the request * @param obj the domain or content object */ public static void setReference(Request request, PersistentObject obj) { Content content; if (obj instanceof Domain) { request.setAttribute("type", "domain"); request.setAttribute("id", ((Domain) obj).getName()); } else { content = (Content) obj; request.setAttribute("type", getCategory(content)); request.setAttribute("id", String.valueOf(content.getId())); } } /** * Processes a request to a template file. The template file name * is relative to the web context directory, and the output MIME * type will always be set to "text/html". * * @param request the request object * @param templateName the template file name */ public static void sendTemplate(Request request, String templateName) { Template template; try { template = TemplateManager.getFileTemplate(templateName); template.processNormal(request, getContentManager()); } catch (ContentException e) { request.sendData("text/plain", "Error: " + e.getMessage()); } catch (TemplateException e) { request.sendData("text/plain", "Error: " + e.getMessage()); } } }