/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2011-2015 ForgeRock AS. */ package org.forgerock.openidm.workflow.activiti.impl; import org.forgerock.openidm.workflow.activiti.ActivitiConstants; import org.activiti.engine.delegate.JavaDelegate; import org.activiti.engine.impl.javax.el.ELContext; import org.activiti.engine.impl.javax.el.ELResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.beans.FeatureDescriptor; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.script.Bindings; import org.activiti.engine.ActivitiException; import org.activiti.engine.impl.context.Context; import org.forgerock.json.JsonValue; import org.forgerock.script.ScriptRegistry; import org.forgerock.openidm.workflow.activiti.impl.session.OpenIDMSession; import org.forgerock.script.ScriptEntry; import org.forgerock.script.ScriptName; import org.forgerock.script.groovy.FunctionClosure; import org.forgerock.util.LazyMap; /** * Custom ExpressionResolver for OpenIDM * * @version $Revision$ $Date$ */ public class OpenIDMELResolver extends ELResolver { private static final Logger LOGGER = LoggerFactory.getLogger(OpenIDMELResolver.class); private Map<String, JavaDelegate> delegateMap = new HashMap<String, JavaDelegate>(); private ScriptRegistry scriptRegistry; public OpenIDMELResolver(Map<String, JavaDelegate> delegateMap) { this.delegateMap = delegateMap; } @Override public Object getValue(ELContext elContext, Object base, Object property) { OpenIDMSession session = Context.getCommandContext().getSession(OpenIDMSession.class); scriptRegistry = session.getOpenIDMScriptRegistry(); Map<String, String> scriptJson = new HashMap<String, String>(3); Bindings bindings = null; String key = (String) property; try { JsonValue openidmContext = (JsonValue) elContext.getELResolver().getValue(elContext, null, ActivitiConstants.OPENIDM_CONTEXT); org.forgerock.services.context.Context context = new ActivitiContext(openidmContext, this.getClass().getClassLoader()); ScriptEntry script = scriptRegistry.takeScript(new ScriptName("ActivitiScript", "groovy")); if (script == null) { scriptJson.put("source", ""); scriptJson.put("type", "groovy"); scriptJson.put("name", "ActivitiScript"); script = scriptRegistry.takeScript(new JsonValue(scriptJson)); } bindings = script.getScriptBindings(context, null); } catch (Exception ex) { LOGGER.error(ex.getMessage(), ex); throw new ActivitiException(ex.getMessage(), ex); } if (base == null) { // according to javadoc, can only be a String if (bindings.containsKey(key)) { elContext.setPropertyResolved(true); return bindings.get(key); } else { for (String name : delegateMap.keySet()) { if (name.equalsIgnoreCase(key)) { elContext.setPropertyResolved(true); return delegateMap.get(name); } } } } //fetching the openidmcontext sets it to true, we need to set it //to false again if the property was not found elContext.setPropertyResolved(false); return null; } @Override public boolean isReadOnly(ELContext context, Object base, Object property) { return true; } @Override public void setValue(ELContext context, Object base, Object property, Object value) { } @Override public Class<?> getCommonPropertyType(ELContext context, Object arg) { return Object.class; } @Override public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object arg) { return null; } @Override public Class<?> getType(ELContext context, Object arg1, Object arg2) { return Object.class; } /** * Called when openidm.xxx() is called from an Expression * @return result of the call */ @Override public Object invoke(ELContext context, Object base, Object method, Class<?>[] paramTypes, Object[] params) { if (base instanceof LazyMap && ((LazyMap)base).containsKey(method)) { context.setPropertyResolved(true); FunctionClosure function = (FunctionClosure)((LazyMap)base).get(method); return function.doCall(params); } return null; } }