/** * Copyright 2011 meltmedia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xchain.namespaces.core; import org.apache.commons.jxpath.JXPathContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xchain.Command; import org.xchain.annotations.Attribute; import org.xchain.annotations.AttributeType; import org.xchain.annotations.Element; import org.xchain.impl.ChainImpl; import org.xchain.framework.jxpath.Scope; import org.xchain.framework.jxpath.ScopedQNameVariables; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; /** * The <code>iterate</code> command will execute its child commands for each element in the object selected by the <code>select</code> attribute. * * <code class="source"> * <xchain:iterate xmlns:xchain="http://www.xchain.org/core/1.0" select="/some/xpath" variable="name"> * ... * </xchain:iterate> * </code> * * @author Christian Trimble * @author Josh Kennedy */ @Element(localName="iterate") public abstract class IterateCommand extends ChainImpl { private static Logger log = LoggerFactory.getLogger(IterateCommand.class); /** * The QName of the variable. */ @Attribute(localName="variable", type=AttributeType.QNAME) public abstract QName getName( JXPathContext context ); public abstract boolean hasName(); /** * The JXPath of the java.util.Iterator object. This method is provided for backwards compatiblity, the * select attribute should be used instead. */ @Attribute(localName="iterator", type=AttributeType.JXPATH_VALUE) public abstract Iterator getIterator( JXPathContext context ); public abstract boolean hasIterator(); /** * The JXPath of the object to iterate. The object can be of type java.util.Iterator, java.util.Enumeration, * java.util.Collection, java.util.Map, or an array. */ @Attribute(localName="select", type=AttributeType.JXPATH_VALUE) public abstract Object getSelect( JXPathContext context ); public abstract boolean hasSelect(); /** * The scope of the variable. Can either be the literal global or local. */ @Attribute(localName="scope", type=AttributeType.LITERAL, defaultValue="request") public abstract Scope getScope(JXPathContext context); public boolean execute( JXPathContext context ) throws Exception { boolean result = false; try { if( log.isDebugEnabled() ) { log.debug("Iterate command called. Has iterator:"+hasIterator()+" Has select:"+hasSelect()); } Iterator iterator = null; Enumeration enumeration = null; Object[] objectArray = null; int index = -1; QName variableName = getName(context); if( log.isDebugEnabled() ) { log.debug("Iterate variable:"+variableName); } // get the scope. Scope scope = getScope(context); ScopedQNameVariables variables = (ScopedQNameVariables)context.getVariables(); if( log.isDebugEnabled() ) { log.debug("Starting iteration process."); } if( hasIterator() ) { iterator = getIterator(context); } else if( hasSelect() ) { Object object = getSelect(context); if( object == null ) { if( log.isDebugEnabled() ) { log.debug("The selected iteration object is null."); } } else if( object instanceof Iterator ) { if( log.isDebugEnabled() ) { log.debug("Iterator selected."); } iterator = (Iterator)object; } else if( object instanceof Enumeration ) { if( log.isDebugEnabled() ) { log.debug("Enumeration selected."); } enumeration = (Enumeration)object; } else if( object instanceof Collection ) { if( log.isDebugEnabled() ) { log.debug("Collection selected."); } iterator = ((Collection)object).iterator(); } else if( object instanceof Map ) { if( log.isDebugEnabled() ) { log.debug("Map selected."); } iterator = ((Map)object).entrySet().iterator(); } else if( object instanceof Object[] ) { objectArray = (Object[])object; index = 0; } else { if( log.isDebugEnabled() ) { log.debug("The selected iteration object is not a supported type: "+object.getClass().getName()); } } } if( iterator != null || enumeration != null || objectArray != null ) { // if the variable has a value, then get it. while( ((iterator != null && iterator.hasNext()) || (enumeration != null && enumeration.hasMoreElements()) || (objectArray != null && index < objectArray.length)) && !result ) { Object value = null; if( iterator != null ) { value = iterator.next(); } else if( enumeration != null ) { value = enumeration.nextElement(); } else { value = objectArray[index++]; } if( log.isDebugEnabled() ) { log.debug("Setting variable name '"+variableName+"' to value '"+value+"' in scope '"+scope+"'."); } variables.declareVariable( variableName, value, scope ); result = super.execute(context); } } else { if( log.isDebugEnabled() ) { log.debug("Skipping iteration due to a null iterator."); } } if( log.isDebugEnabled() ) { log.debug("Iteration complete."); } } catch( Exception e ) { if( log.isDebugEnabled() ) { log.debug("Could not iterate due to exception.", e); } throw e; } catch( Error err ) { if( log.isDebugEnabled() ) { log.debug("Could not iterate due to exception.", err); } throw err; } // return false and allow other chains to execute. return result; } }