You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@maven.apache.org by ka...@apache.org on 2002/12/21 05:30:47 UTC
cvs commit: jakarta-turbine-maven/src/java/org/apache/maven/jelly/tags/velocity JellyContextAdapter.java MergeTag.java
kaz 2002/12/20 20:30:47
Modified: src/java/org/apache/maven/jelly/tags/velocity
JellyContextAdapter.java MergeTag.java
Added: src/test/java/org/apache/maven/jelly/tags/velocity
JellyContextAdapterTest.java
Log:
Updated the Jelly Velocity taglib. A new attribute has been added to
the <velocity:merge> tag called 'readOnly'. It is a boolean value that
specifies the JellyContext is read-only or read-write. Read-only will
prevent modifications to the Velocity context from propogating back to
the JellyContext. Read-write will propogate modifications. The default
is read-only if the attribute is not specified. For example (taken from
the uberjar plugin),
<velocity:merge
name="${confdir}"
template="${plugin.dir}/src/conf/classworlds.conf"/>
The above example would create a read-only adapter preventing Velocity
from affecting the JellyContext. However, the following example would
allow changes to affect the JellyContext:
<velocity:merge
name="${confdir}"
readOnly="false"
template="${plugin.dir}/src/conf/classworlds.conf"/>
Behind the covers, the JellyContextAdapter, has been modified to
accomodate the above changes. The setReadOnly(boolean) method specifies
the behavior that should be used. When used in read-only mode, all
modifications made by Velocity are done to a private context (to avoid
modifying the JellyContext). In this case, lookups will be performed on
both contexts, first the private context, then the JellyContext.
Read-write mode maps directly to the JellyContext.
A unit test has also been created to test the JellyContextAdapter.
Finally, thanks to Jon for suggesting that the default behavior of the
adapter should be read-only.
Revision Changes Path
1.1 jakarta-turbine-maven/src/test/java/org/apache/maven/jelly/tags/velocity/JellyContextAdapterTest.java
Index: JellyContextAdapterTest.java
===================================================================
package org.apache.maven.jelly.tags.velocity;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, 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" and "Apache Software Foundation" and
* "Apache Maven" 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",
* "Apache Maven", 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 (INCLUDING, 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. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.collections.CollectionUtils;
/**
* Unit test for <code>JellyContextAdapter</code>.
*
* @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
* @version $Id: JellyContextAdapterTest.java,v 1.1 2002/12/21 04:30:47 kaz Exp $
*/
public class JellyContextAdapterTest extends TestCase
{
JellyContext jellyContext;
JellyContextAdapter adapter;
/**
* Create the test case
*
* @param testName name of the test case
*/
public JellyContextAdapterTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( JellyContextAdapterTest.class );
}
public void setUp()
{
jellyContext = new JellyContext();
adapter = new JellyContextAdapter( jellyContext );
}
/**
* Test the behavior of null keys.
*/
public void testNullKey()
{
adapter.setReadOnly( false );
adapter.put( null, new Object() );
assertTrue( adapter.get( null ) == null );
}
/**
* Test the behavior of null values.
*/
public void testNullValue()
{
adapter.setReadOnly( false );
adapter.put( "key", null );
assertTrue( adapter.get( "key" ) == null );
}
/**
* Test that items can be added and retrieved from a read-write
* adpater. Also verify the key/value pair was actually inserted
* into the JellyContext.
*/
public void testReadWritePut()
{
Object value = new Object();
adapter.setReadOnly( false );
adapter.put( "key", value );
assertTrue( "adapter: did not return the original value",
adapter.get( "key" ) == value );
assertTrue( "jellyContext: did not return the original value",
jellyContext.getVariable( "key" ) == value );
}
/**
* Test that items can be added and retrieved from a read-only
* adapter. Also verify the key/value pair was not inserted into
* the JellyContext.
*/
public void testReadOnlyPut()
{
Object value = new Object();
adapter.setReadOnly( true );
adapter.put( "key", value );
assertTrue( "adapter: did not return the original value",
adapter.get( "key" ) == value );
assertTrue( "jellyContext: must return null when adapter is readonly",
jellyContext.getVariable( "key" ) == null );
}
/**
* Test that items can be removed from a read-write context. Also
* verify that the item is removed from the JellyContext.
*/
public void testReadWriteRemove()
{
Object value = new Object();
adapter.setReadOnly( false );
adapter.put( "key", value );
Object oldValue = adapter.remove( "key" );
assertTrue( "Value returned from remove() is not the original",
value == oldValue );
assertTrue( "adapter: after removal of key, value should be null",
adapter.get( "key" ) == null );
assertTrue( "jellyContext: after removal of key, value should be null",
jellyContext.getVariable( "key" ) == null );
assertTrue( "Removal of non-existent key should return null",
adapter.remove( "non-existent key" ) == null );
}
/**
* Test that items can be removed from a read-only context. Also
* verify that the JellyContext is not impacted by removal of keys.
*/
public void testReadOnlyRemove()
{
Object value = new Object();
adapter.setReadOnly( true );
adapter.put( "key", value );
Object oldValue = adapter.remove( "key" );
assertTrue( "Value returned from remove() is not the original",
value == oldValue );
assertTrue( "adapter: after removal of key, value should be null",
adapter.get( "key" ) == null );
assertTrue( "jellyContext: value should not be affected.",
jellyContext.getVariable( "key" ) == null );
assertTrue( "Removal of non-existent key should return null",
adapter.remove( "non-existent key" ) == null );
}
/**
* Test that items can shadow or hide items in the JellyContext.
* Removal of a key in the private context will unveil the key in
* the JellyContext if it exists.
*/
public void testReadOnlyShadowingRemove()
{
Object value1 = new Object();
Object value2 = new Object();
adapter.setReadOnly( true );
adapter.put( "key", value1 );
jellyContext.setVariable( "key", value2 );
assertTrue( "adapter: before removal of key, value should be 1",
adapter.get( "key" ) == value1 );
adapter.remove( "key" );
assertTrue( "adapter: after removal of key, value should be 2",
adapter.get( "key" ) == value2 );
assertTrue( "jellyContext: value should not be affected.",
jellyContext.getVariable( "key" ) == value2 );
}
/**
* Test the containsKey method in a read-write adapter.
*/
public void testReadWriteContainsKey()
{
Object value1 = new Object();
Object value2 = new Object();
adapter.setReadOnly( false );
adapter.put( "key1", value1 );
jellyContext.setVariable( "key2", value2 );
assertTrue( "adapter: did not contain the key",
adapter.containsKey( "key1" ) );
assertTrue( "adapter: should contain the key",
adapter.containsKey( "key2" ) );
assertTrue( "jellyContext: did not contain the key",
jellyContext.getVariable( "key1" ) != null );
}
/**
* Test the containsKey method in a read-only adapter.
*/
public void testReadOnlyContainsKey()
{
Object value1= new Object();
Object value2 = new Object();
adapter.setReadOnly( true );
adapter.put( "key1", value1 );
jellyContext.setVariable( "key2", value2 );
assertTrue( "adapter: did not contain the key",
adapter.containsKey( "key1" ) );
assertTrue( "adapter: should not contain the key",
adapter.containsKey( "key2" ) );
assertTrue( "jellyContext: should not contain the key",
jellyContext.getVariable( "key1" ) == null );
}
/**
* Test the getKeys method of a read-write adapter.
*/
public void testReadWriteGetKeys()
{
Object value1 = new Object();
Object value2 = new Object();
Object value3 = new Object();
adapter.setReadOnly( false );
adapter.put( "key1", value1 );
adapter.put( "key2", value2 );
jellyContext.setVariable( "key3", value3 );
Set expectedKeys = new HashSet();
expectedKeys.add( "key1" );
expectedKeys.add( "key2" );
expectedKeys.add( "key3" );
Set actualKeys = new HashSet();
CollectionUtils.addAll(actualKeys, adapter.getKeys());
assertTrue( "adapter: does not contain the correct key set",
actualKeys.containsAll( expectedKeys ) );
}
/**
* Test the getKeys method of a read-only adapter.
*/
public void testReadOnlyGetKeys()
{
Object value1 = new Object();
Object value2 = new Object();
Object value3 = new Object();
adapter.setReadOnly( true );
adapter.put( "key1", value1 );
adapter.put( "key2", value2 );
jellyContext.setVariable( "key3", value3 );
Set expectedKeys = new HashSet();
expectedKeys.add( "key1" );
expectedKeys.add( "key2" );
Set actualKeys = new HashSet();
CollectionUtils.addAll(actualKeys, adapter.getKeys());
assertTrue( "adapter: does not contain the correct key set",
actualKeys.containsAll( expectedKeys ) );
}
}
1.2 +90 -7 jakarta-turbine-maven/src/java/org/apache/maven/jelly/tags/velocity/JellyContextAdapter.java
Index: JellyContextAdapter.java
===================================================================
RCS file: /home/cvs/jakarta-turbine-maven/src/java/org/apache/maven/jelly/tags/velocity/JellyContextAdapter.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JellyContextAdapter.java 16 Dec 2002 01:01:00 -0000 1.1
+++ JellyContextAdapter.java 21 Dec 2002 04:30:47 -0000 1.2
@@ -56,19 +56,36 @@
* ====================================================================
*/
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+
import org.apache.commons.jelly.JellyContext;
import org.apache.velocity.context.Context;
/**
- * Adapts a JellyContext for use as a Velocity Context.
+ * Adapts a JellyContext for use as a Velocity Context. This context
+ * can be used in either read-only or read-write mode. When used as a
+ * read-only adapter, items <tt>put</tt> or <tt>remove</tt>ed from the
+ * Velocity context are not permitted to propogate to the JellyContext,
+ * which is the default behavior. The adapter can also be used in a
+ * read-write mode. This permits changes made by Velocity to propogate
+ * to the JellyContext.
*
* @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
* @version $Id$
*/
class JellyContextAdapter implements Context
{
+ /** Flag to indicate read-only or read-write mode */
+ private boolean readOnly = true;
+
+ /** The JellyContext being adapted */
private JellyContext jellyContext;
+ /** The store for Velocity in the event the adpater is read-only */
+ private HashMap privateContext = new HashMap();
+
/**
* Constructor.
*
@@ -78,6 +95,32 @@
{
this.jellyContext = jellyContext;
}
+
+ /**
+ * Sets the read-only flag for this adapter. If the read-only flag
+ * is set, changes to the Velocity Context will not be propogated to
+ * the JellyContext. Turning the read-only flag off enables changes
+ * to propogate.
+ *
+ * @param readOnly If this parameter is <tt>true</tt>, the adapter
+ * becomes read-only. Setting the parameter to <tt>false</tt> the
+ * adapter becomes read-write.
+ */
+ public void setReadOnly(boolean readOnly)
+ {
+ this.readOnly = readOnly;
+ }
+
+ /**
+ * Tests if the adapter is read-only.
+ *
+ * @return <tt>true</tt> if the adpater is read-only; otherwise
+ * returns <tt>false</tt>.
+ */
+ public boolean isReadOnly()
+ {
+ return readOnly;
+ }
public boolean containsKey( Object key )
{
@@ -85,6 +128,12 @@
{
return false;
}
+
+ if ( readOnly && privateContext.containsKey( key ) )
+ {
+ return true;
+ }
+
return jellyContext.getVariable( key.toString() ) != null ? true : false;
}
@@ -95,35 +144,69 @@
return null;
}
+ if ( readOnly && privateContext.containsKey( key ) )
+ {
+ return privateContext.get( key );
+ }
+
return jellyContext.getVariable( key );
}
public Object[] getKeys()
{
- return jellyContext.getVariables().keySet().toArray();
+ Set keys = jellyContext.getVariables().keySet();
+
+ if ( readOnly )
+ {
+ HashSet combinedKeys = new HashSet( keys );
+ combinedKeys.addAll( privateContext.keySet() );
+ keys = combinedKeys;
+ }
+
+ return keys.toArray();
}
public Object put( String key, Object value )
{
+ Object oldValue;
+
if ( key == null || value == null )
{
return null;
}
- Object oldValue = jellyContext.getVariable( key );
- jellyContext.setVariable( key, value );
+ if ( readOnly )
+ {
+ oldValue = privateContext.put( key, value );
+ }
+ else
+ {
+ oldValue = jellyContext.getVariable( key );
+ jellyContext.setVariable( key, value );
+ }
+
return oldValue;
}
public Object remove( Object key )
{
+ Object oldValue;
+
if ( key == null )
{
return null;
}
- Object oldValue = jellyContext.getVariable( key.toString() );
- jellyContext.removeVariable( key.toString() );
+ if ( readOnly )
+ {
+ oldValue = privateContext.remove( key );
+ }
+ else
+ {
+ oldValue = jellyContext.getVariable( key.toString() );
+ jellyContext.removeVariable( key.toString() );
+ }
+
return oldValue;
}
}
1.3 +23 -5 jakarta-turbine-maven/src/java/org/apache/maven/jelly/tags/velocity/MergeTag.java
Index: MergeTag.java
===================================================================
RCS file: /home/cvs/jakarta-turbine-maven/src/java/org/apache/maven/jelly/tags/velocity/MergeTag.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- MergeTag.java 18 Dec 2002 17:11:02 -0000 1.2
+++ MergeTag.java 21 Dec 2002 04:30:47 -0000 1.3
@@ -75,11 +75,14 @@
*/
public class MergeTag extends VelocityTagSupport
{
+ private static final String ENCODING = "ISO-8859-1";
+
private String var;
private String name;
private String template;
private String inputEncoding;
private String outputEncoding;
+ private boolean readOnly = true;
// -- Tag interface -----------------------------------------------------
@@ -94,7 +97,7 @@
{
Writer writer = new OutputStreamWriter(
new FileOutputStream( name ),
- outputEncoding == null ? "ISO-8859-1" : outputEncoding );
+ outputEncoding == null ? ENCODING : outputEncoding );
mergeTemplate( writer );
writer.close();
}
@@ -145,6 +148,20 @@
{
this.template = template;
}
+
+ /**
+ * Sets the read-only flag for this adapter which prevents
+ * modifications in the Velocity context from propogating to the
+ * JellyContext.
+ *
+ * @param readOnly <tt>true</tt> prevents modifications from
+ * propogating (the default), or <tt>false</tt> which permits
+ * modifications.
+ */
+ public void setReadOnly( boolean readOnly )
+ {
+ this.readOnly = readOnly;
+ }
/**
* Sets the output encoding mode which defaults to ISO-8859-1 used
@@ -179,12 +196,13 @@
*/
private void mergeTemplate( Writer writer ) throws Exception
{
- Context velocityContext = new JellyContextAdapter( getContext() );
+ JellyContextAdapter adapter = new JellyContextAdapter( getContext() );
+ adapter.setReadOnly( readOnly );
getVelocityEngine().mergeTemplate(
template,
- inputEncoding == null ? "ISO-8859-1" : inputEncoding,
- velocityContext,
+ inputEncoding == null ? ENCODING : inputEncoding,
+ adapter,
writer );
}
}