/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.common.impl.content; import ch.entwine.weblounge.common.impl.security.UserImpl; import ch.entwine.weblounge.common.impl.util.WebloungeDateFormat; import ch.entwine.weblounge.common.impl.util.xml.XPathHelper; import ch.entwine.weblounge.common.security.User; import org.w3c.dom.Node; import java.text.ParseException; import java.util.Date; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathFactory; /** * The creation context contains information about when an object was created * and who the creator was. It can be used by <code>Creatable</code> objects as * the backing implementation. * <p> * The context adds additional means of specifying and querying creator and * creation date. It also allows for easy serialization and deserialization of * <code>Creatable</code> data. * <p> * Following is an example of the data structure that the modification context * is able to handle: * * <pre> * <created> * <user id="john" realm="testland">John Doe</user> * <date>2009/11/06 08:52:52 GMT</date> * </created> * </pre> * * @see ch.entwine.weblounge.common.content.Creatable */ public class CreationContext implements Cloneable { /** Creation date */ protected Date creationDate = null; /** Creator */ protected User creator = null; /** * Creates a new and empty modification context. */ public CreationContext() { this.creationDate = cutOffMillis(new Date()); } /** * Returns the creation date. * * @return the creation date */ public Date getCreationDate() { return creationDate; } /** * Returns the user that created the object. * * @return the creator */ public User getCreator() { return creator; } /** * Sets the creation date and the user who created the object. * <p> * Note that this method will cut off the millisecond portion of the date. * </p> * * @param creator * the user creating the object * @param creationDate * the date of creation */ public void setCreated(User user, Date date) { this.creator = user; this.creationDate = cutOffMillis(date); } /** * Sets the creation date. * <p> * Note that this method will cut off the millisecond portion of the date. * </p> * * @param date * the creation date */ public void setCreationDate(Date date) { this.creationDate = cutOffMillis(date); } /** * Sets the user that created the object. * * @param user * the creator */ public void setCreator(User user) { this.creator = user; } /** * Returns <code>true</code> if this context was created after the given date. * * @param date * the date to compare to * @return <code>true</code> is this context was created after the given date */ public boolean isCreatedAfter(Date date) { return creationDate != null && creationDate.after(cutOffMillis(date)); } /** * Creates a clone of this <code>CreationContext</code>. * * @return the cloned creation context */ public Object clone() throws CloneNotSupportedException { CreationContext ctxt = (CreationContext) super.clone(); if (creator != null) ctxt.creator = (User) creator.clone(); if (creationDate != null) ctxt.creationDate = (Date) creationDate.clone(); return ctxt; } /** * Cut off the milliseconds from the date. * * @param date * with milliseconds * @return date without milliseconds */ private Date cutOffMillis(Date date) { if (date == null) return null; long time = date.getTime() / 1000L; return new Date(time * 1000L); } /** * Initializes this context from an XML node that was generated using * {@link #toXml()}. * <p> * To speed things up, you might consider using the second signature that uses * an existing <code>XPath</code> instance instead of creating a new one. * * @param context * the creation context node * @throws IllegalStateException * if the context cannot be parsed * @see #fromXml(Node, XPath) * @see #toXml() */ public static CreationContext fromXml(Node context) throws IllegalStateException { XPath xpath = XPathFactory.newInstance().newXPath(); return fromXml(context, xpath); } /** * Initializes this context from an XML node that was generated using * {@link #toXml()}. * * @param context * the creation context node * @param xpathProcessor * xpath processor to use * @throws IllegalStateException * if the context cannot be parsed * @see #toXml() */ public static CreationContext fromXml(Node context, XPath xpathProcessor) throws IllegalStateException { Node contextRoot = XPathHelper.select(context, "/created", xpathProcessor); if (contextRoot == null) return null; CreationContext ctx = new CreationContext(); // Creator Node creator = XPathHelper.select(contextRoot, "/created/user", xpathProcessor); if (creator != null) ctx.setCreator(UserImpl.fromXml(creator, xpathProcessor)); // Creation date String date = XPathHelper.valueOf(contextRoot, "/created/date", xpathProcessor); if (date != null) try { ctx.setCreationDate(WebloungeDateFormat.parseStatic(date)); } catch (ParseException e) { throw new IllegalStateException("The creation date '" + date + "' cannot be parsed", e); } return ctx; } /** * Returns an <code>XML</code> representation of the context, that will look * similar to the following example: * * <pre> * <created> * <user id="john" realm="testland">John Doe</user> * <date>2009/11/06 08:52:52 GMT</date> * </created> * </pre> * * Use {@link #fromXml(Node))} or {@link #fromXml(Node, XPath)} to create a * <code>CreationContext</code> from the serialized output of this method. * * @return the <code>XML</code> representation of the context * @see #fromXml(Node) * @see #fromXml(Node, XPath) */ public String toXml() { StringBuffer b = new StringBuffer(); b.append("<created>"); // User if (creator != null) { b.append("<user"); // id b.append(" id=\""); b.append(creator.getLogin()); b.append("\""); // realm if (creator.getRealm() != null) { b.append(" realm=\""); b.append(creator.getRealm()); b.append("\""); } b.append(">"); // name if (creator.getName() != null) { b.append("<![CDATA[").append(creator.getName()).append("]]>"); } b.append("</user>"); } // Date if (creationDate != null) { b.append("<date>"); b.append(WebloungeDateFormat.formatStatic(creationDate)); b.append("</date>"); } b.append("</created>"); return b.toString(); } }