/** * Copyright 2013-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * 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 net.roboconf.dm.templating.internal.helpers; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.logging.Logger; import net.roboconf.core.utils.Utils; import net.roboconf.dm.templating.internal.contexts.ApplicationContextBean; import net.roboconf.dm.templating.internal.contexts.InstanceContextBean; import org.apache.commons.lang3.StringUtils; import com.github.jknack.handlebars.Context; import com.github.jknack.handlebars.Helper; import com.github.jknack.handlebars.Options; /** * Helper needed to select all the instances matching a given criterion. * @author Pierre Bourret - Université Joseph Fourier */ public class AllHelper implements Helper<Object> { public static final String NAME = "all"; private final Logger logger = Logger.getLogger( getClass().getName()); /** * Selects instances according to a selection path. * <p>For example:</p> * <pre> * {{#all children path="/VM/Apache" installer="script"}} * {{path}} * {{/all}} * </pre> */ @Override public CharSequence apply( final Object computedContext, final Options options ) throws IOException { // Get parameters Object context = options.context.model(); String componentPath = null; if( computedContext instanceof String ) componentPath = (String) computedContext; if( Utils.isEmptyOrWhitespaces( componentPath )) componentPath = InstanceFilter.JOKER; // Process them CharSequence result = StringUtils.EMPTY; if (context instanceof ApplicationContextBean) { // Implicit: all instances of the application. result = safeApply(((ApplicationContextBean) context).getInstances(), options, componentPath ); } else if (context instanceof InstanceContextBean) { // Implicit: all descendants of the instance. result = safeApply( descendantInstances((InstanceContextBean) context), options, componentPath ); } else { this.logger.warning( "An unexpected context was received: " + (context == null ? null : context.getClass())); } return result; } /** * Same as above, but with type-safe arguments. * * @param instances the instances to which this helper is applied. * @param options the options of this helper invocation. * @return a string result. * @throws IOException if a template cannot be loaded. */ private String safeApply( Collection<InstanceContextBean> instances, Options options, String componentPath ) throws IOException { // Parse the filter. String installerName = (String) options.hash.get( "installer" ); final InstanceFilter filter = InstanceFilter.createFilter( componentPath, installerName ); // Apply the filter. final Collection<InstanceContextBean> selectedInstances = filter.apply( instances ); // Apply the content template of the helper to each selected instance. final StringBuilder buffer = new StringBuilder(); final Context parent = options.context; int index = 0; final int last = selectedInstances.size() - 1; for( final InstanceContextBean instance : selectedInstances ) { final Context current = Context.newBuilder( parent, instance ) .combine( "@index", index ) .combine( "@first", index == 0 ? "first" : "" ) .combine( "@last", index == last ? "last" : "" ) .combine( "@odd", index % 2 == 0 ? "" : "odd" ) .combine( "@even", index % 2 == 0 ? "even" : "" ) .build(); index++; buffer.append( options.fn( current )); } return buffer.toString(); } /** * Returns all the descendant instances of the given instance. * @param instance the instance which descendants must be retrieved. * @return the descendants of the given instance. */ private static Collection<InstanceContextBean> descendantInstances( final InstanceContextBean instance ) { final Collection<InstanceContextBean> result = new ArrayList<InstanceContextBean>(); for (final InstanceContextBean child : instance.getChildren()) { result.add( child ); result.addAll( descendantInstances( child ) ); } return result; } }