You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by hu...@apache.org on 2002/07/08 02:16:00 UTC
cvs commit: xml-cocoon2/src/scratchpad/src/org/apache/cocoon/selection DateSelector.java
huber 2002/07/07 17:16:00
Added: src/scratchpad/src/org/apache/cocoon/selection
DateSelector.java
Log:
A DateSelector selection depends on date/time value
Revision Changes Path
1.1 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/selection/DateSelector.java
Index: DateSelector.java
===================================================================
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
apache@apache.org.
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <st...@apache.org>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.selection;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* A <code>Selector</code> depending on current date, and time.
* <p>
* This selector matches when a configured date is before, respectivly
* after the current date, and time.
* </p>
* <p>
* You may want to use this selector to make the pipeline behaviour time
* dependent.
* </p>
* <p>
* The configuration of DataSelector configures for a symbolic name
* a compare-mode, and a date-time value.
* <br/>
* The compare mode is specified by the element name before, or after.
* The date-time value is specified by the attribute date. The attribute
* dateformat specifies the dateformat of the date-time value. Time only values
* are relative to the current date. Optionally you specify a country, and
* a language attribute for specifying the locale used in the date-value parsing.
* Per default the default locale is used.
* </p>
* <p>
* The following configuration example, sets partition a day into four time
* areas, each spanning six hours, giving them symbolic names night, morning,
* afternoon, and evening.
* </p>
* <pre><code>
* <map:components>
* ...
* <map:selectors default="browser">
* ...
* <map:selector type="date" src="org.apache.cocoon.selection.DateSelector">
* <before name="night" date="06:00:00" dateformat="HH:mm:ss"/>
* <before name="morning" date="12:00:00" dateformat="HH:mm:ss"/>
* <before name="afternoon" date="18:00:00" dateformat="HH:mm:ss"/>
* <before name="evening" date="23:59:59" dateformat="HH:mm:ss"/>
* </map:selector>
* ...
* </map:selectors>
* ...
* </map:components>
* </code></pre>
* <p>
* The above date selector definition is used to control the behaviour of a
* pipeline processing depending on the current time of day.
* </p>
* <pre><code>
* <map:pipelines>
* <map:pipeline>
* ...
* <map:match pattern="&asterik;&asterik;/resources/*.css">
* <map:select type="date">
* <map:when test="night">
* <!-- do something for night publishing -->
* <map:read src="resources/{2}-night.css" mime-type="text/css>
* </map:when>
* <map:when test="morning">
* <!-- do something for night publishing -->
* <map:read src="resources/{2}-morning.css" mime-type="text/css>
* </map:when>
* ...
* <map:otherwise>
* <!-- define for completness, and if selecting fails due to errors -->
* </map:otherwise>
* </map:select>
* </map:pipeline>
* </map:pipelines>
* </code></pre>
*
* @author <a href="mailto:huber@apache.org">Bernhard Huber</a>
* @version CVS $Id: DateSelector.java,v 1.1 2002/07/08 00:15:59 huber Exp $
*/
public class DateSelector extends AbstractSwitchSelector
implements Configurable, ThreadSafe {
/** the configuration
*/
private Configuration config;
final public static String AFTER_ELEMENT = "after";
final public static String BEFORE_ELEMENT = "before";
final public static String NAME_ATTR = "name";
final public static String DATE_ATTR = "date";
final public static String DATEFORMAT_ATTR = "dateformat";
final public static String LANGUAGE_ATTR = "language";
final public static String COUNTRY_ATTR = "country";
public void configure(Configuration config) throws ConfigurationException {
this.config = config;
}
protected void configure( final Configuration conf, final String confName, final Map configMap ) {
final Configuration[] confs = conf.getChildren( confName );
String name = null;
String date = null;
String dateformat = null;
String language = null;
String country = null;
final Calendar now = Calendar.getInstance();
for (int i = 0; i < confs.length; i++ ) {
try {
name = confs[i].getAttribute( NAME_ATTR );
date = confs[i].getAttribute( DATE_ATTR );
dateformat = confs[i].getAttribute( DATEFORMAT_ATTR, null );
language = confs[i].getAttribute( LANGUAGE_ATTR, null );
country = confs[i].getAttribute( COUNTRY_ATTR, null);
Date parsed_date = null;
SimpleDateFormat sdf = null;
if (dateformat != null && language != null && country != null) {
Locale locale = new Locale( language, country );
sdf = new SimpleDateFormat( dateformat, locale );
} else if (dateformat != null) {
sdf = new SimpleDateFormat( dateformat );
} else {
sdf = new SimpleDateFormat();
}
sdf.parse( date );
Calendar parsed_calendar = sdf.getCalendar();
setUnsetFields( parsed_calendar, now );
parsed_date = parsed_calendar.getTime();
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug( "Parsed " + DATE_ATTR + " '" + String.valueOf(date) + "' to " +
"date object " + parsed_date.toString() );
}
if (parsed_date != null) {
// associate the name with associate date, and the compare-mode
configMap.put( name,
new DateComparator( parsed_date, confName ) );
}
} catch (Exception e) {
if (this.getLogger().isErrorEnabled()) {
this.getLogger().error(
"Cannot parse date " + String.valueOf(date) + ", using " +
NAME_ATTR + " " + String.valueOf( name ) + ", " +
DATE_ATTR + " " + String.valueOf( date ) + ", " +
DATEFORMAT_ATTR + " " + String.valueOf( dateformat ) + ", " +
LANGUAGE_ATTR + " " + String.valueOf( language ) + ", " +
COUNTRY_ATTR + " " + String.valueOf( country )
, e );
}
}
}
}
/**
* set fields which are not set by parsing the date attribute value
*
* @param cal Calendar parsed in
* @param defautl_cal Calendar object providing default value for unset
* fields of cal
*/
protected void setUnsetFields( Calendar cal, Calendar default_cal ) {
// set fields which are not set by parsing date attribute
if (!cal.isSet( Calendar.YEAR )) {
cal.set( Calendar.YEAR, default_cal.get( Calendar.YEAR ) );
}
if (!cal.isSet( Calendar.MONTH )) {
cal.set( Calendar.MONTH, default_cal.get( Calendar.MONTH ) );
}
if (!cal.isSet( Calendar.DAY_OF_MONTH )) {
cal.set( Calendar.DAY_OF_MONTH, default_cal.get( Calendar.DAY_OF_MONTH ) );
}
if (!cal.isSet( Calendar.HOUR_OF_DAY )) {
cal.set( Calendar.HOUR_OF_DAY, default_cal.get( Calendar.HOUR_OF_DAY ) );
}
if (!cal.isSet( Calendar.MINUTE )) {
cal.set( Calendar.MINUTE, default_cal.get( Calendar.MINUTE ) );
}
if (!cal.isSet( Calendar.SECOND )) {
cal.set( Calendar.SECOND, default_cal.get( Calendar.SECOND ) );
}
//
}
/**
* create an object representing a context for multiple select/when
* invocations
*
* @param objectModel the objectModel of the pipeline processing
* @param paramters unused here
* @return Object which is an object of class DataSelectorContext
*/
public Object getSelectorContext(Map objectModel, Parameters parameters) {
// Inform proxies that response varies over time of request, which
// ASFAIK not a specific header fields, thus Vary is set to *
// Seems that caching is not possible for this resource
ObjectModelHelper.getResponse(objectModel).addHeader("Vary", "*");
// 1 create map : name -> { date, [after|before] } from configuration
Map map = new HashMap();
configure( config, BEFORE_ELEMENT, map );
configure( config, AFTER_ELEMENT, map );
// 2 create SelectorContext
DateSelectorContext csc = new DateSelectorContext();
// 3 precalculate result of comparing current date, and configuration map
csc.setup( map );
return csc;
}
/**
* Evaluate select for a given expression
*
* @param the expression to test against, as now expression
* should be a name defined as <code>NAME_ATTR</code> in the
* configuration section of this selector
* @param selectorContext is the SelectorContext set up by
* the getSelectorContext() method
* @return true if expression defining a name which yields
* true comparing the current date set in getSelectorContext,
* and the configured comparison, referenced by the
* expression name value.
*/
public boolean select(String expression, Object selectorContext) {
if (selectorContext == null) {
getLogger().debug("selectorContext is null!" );
return false;
}
// let SelectorContext do the work
DateSelectorContext csc = (DateSelectorContext)selectorContext;
return csc.select(expression);
}
/**
* A helper class to store <code>Date, and compare-mode [after|before]</code>.
* <p>For each configuration entry the compare-mode
* <code>[before|after]</code> is stored, and the date value associated with it.
* </p>
* <p>
* The 'main' method of this class is providing a compareTo method for easily comparing
* a given date to the configured compare-mode, and date.
* </p>
*/
private static class DateComparator {
/** the configured date value
*/
private Date date;
/** indicator if after comparison should be performed
*/
private boolean isCompareAfter;
/** indicator if before comparison shoulde be performed
*/
private boolean isCompareBefore;
final String AFTER_COMPARATOR_MODE = "after";
final String BEFORE_COMPARATOR_MODE = "before";
public DateComparator( Date d, String comparator ) {
this.date = d;
this.isCompareAfter = AFTER_COMPARATOR_MODE.equalsIgnoreCase( comparator );
this.isCompareBefore = BEFORE_COMPARATOR_MODE.equalsIgnoreCase( comparator );
}
public Date getDate() {
return this.date;
}
public boolean isCompareAfter() {
return this.isCompareAfter;
}
public boolean isCompareBefore() {
return this.isCompareBefore();
}
/**
* Compare when to date value of this object.
* <p>
* Depending on the comparison mode the result of
* <code>now.after( date )</code>, or <code>now.before( date )</code>
* is returned.
* </p>
* @param now the current date and time value
* @return true iff depending on compare-mode
* <code>now.after( date)</code>, or <code>now.before( date )</code>
* yield true
*/
public boolean compareTo( Date now ) {
if (isCompareAfter) {
return now.after( date );
} else if (isCompareBefore) {
return now.before( date );
} else {
return now.compareTo( date) == 0;
}
}
}
/**
* A SelectorContext for this Selector
* <p>
* This SelectorContext compares the configured date values in this context,
* and stores only configure name attributes of comparison yielding true,
* reducing the comparsion effort.
* </p>
*/
private class DateSelectorContext {
Date now;
HashSet set;
public DateSelectorContext() {
now = new Date();
set = new HashSet();
}
public void setup( final Map map ) {
Iterator i = map.entrySet().iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
final String name = (String)entry.getKey();
final DateComparator dc = (DateComparator)entry.getValue();
if (getLogger().isDebugEnabled()) {
getLogger().debug(
"Compare name " + name + " having date " + String.valueOf( dc.getDate() ) + " to " +
String.valueOf( now ) );
}
// only store name in set iff comparison is true
if (dc.compareTo( now )) {
if (getLogger().isDebugEnabled()) {
getLogger().debug(
"Storing name " + String.valueOf( name ) + " as it yielded true " );
}
this.set.add( name );
}
}
}
/**
* Select yields true iff expression is member of the precalculated set.
* As the set may contain various elements the order of checking elements
* is important, and should be considered in the <map:select> sequence.
*
* @param expression a symbolic name which may match member of set
* @return true iff expression is member of set
*/
public boolean select( String expression ) {
return this.set.contains( expression );
}
}
}
----------------------------------------------------------------------
In case of troubles, e-mail: webmaster@xml.apache.org
To unsubscribe, e-mail: cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org