/** * Copyright (C) 2013 BonitaSoft S.A. * BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2.0 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.bonitasoft.web.rest.server.datastore.bpm.flownode; import static org.bonitasoft.web.toolkit.client.common.util.StringUtil.isBlank; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.bonitasoft.engine.bpm.data.DataInstance; import org.bonitasoft.engine.bpm.flownode.ActivityInstance; import org.bonitasoft.engine.bpm.flownode.ActivityInstanceNotFoundException; import org.bonitasoft.engine.bpm.flownode.ActivityStates; import org.bonitasoft.engine.search.SearchOptionsBuilder; import org.bonitasoft.engine.search.SearchResult; import org.bonitasoft.engine.session.APISession; import org.bonitasoft.web.rest.model.bpm.flownode.ActivityDefinition; import org.bonitasoft.web.rest.model.bpm.flownode.ActivityItem; import org.bonitasoft.web.rest.model.bpm.flownode.FlowNodeItem; import org.bonitasoft.web.rest.model.bpm.flownode.HumanTaskItem; import org.bonitasoft.web.rest.server.datastore.converter.ActivityAttributeConverter; import org.bonitasoft.web.rest.server.datastore.filter.ActivityFilterCreator; import org.bonitasoft.web.rest.server.datastore.filter.Filters; import org.bonitasoft.web.rest.server.datastore.utils.SearchOptionsCreator; import org.bonitasoft.web.rest.server.datastore.utils.Sorts; import org.bonitasoft.web.rest.server.datastore.utils.VariableMapper; import org.bonitasoft.web.rest.server.datastore.utils.VariablesMapper; import org.bonitasoft.web.rest.server.engineclient.ActivityEngineClient; import org.bonitasoft.web.rest.server.engineclient.EngineAPIAccessor; import org.bonitasoft.web.rest.server.engineclient.EngineClientFactory; import org.bonitasoft.web.rest.server.framework.api.DatastoreHasGet; import org.bonitasoft.web.rest.server.framework.api.DatastoreHasUpdate; import org.bonitasoft.web.toolkit.client.common.exception.api.APIException; import org.bonitasoft.web.toolkit.client.common.exception.api.APIItemNotFoundException; import org.bonitasoft.web.toolkit.client.common.util.MapUtil; import org.bonitasoft.web.toolkit.client.data.APIID; /** * @author Séverin Moussel * */ public class AbstractActivityDatastore<CONSOLE_ITEM extends ActivityItem, ENGINE_ITEM extends ActivityInstance> extends AbstractFlowNodeDatastore<CONSOLE_ITEM, ENGINE_ITEM> implements DatastoreHasGet<CONSOLE_ITEM>, DatastoreHasUpdate<CONSOLE_ITEM> { public AbstractActivityDatastore(final APISession engineSession) { super(engineSession); } /** * Fill a console item using the engine item passed. * * @param result * The console item to fill * @param item * The engine item to use for filling * @return This method returns the result parameter passed. */ protected static ActivityItem fillConsoleItem(final ActivityItem result, final ActivityInstance item) { FlowNodeDatastore.fillConsoleItem(result, item); result.setReachStateDate(item.getReachedStateDate()); result.setLastUpdateDate(item.getLastUpdateDate()); return result; } @Override public CONSOLE_ITEM get(final APIID id) { try { @SuppressWarnings("unchecked") final ENGINE_ITEM activityInstance = (ENGINE_ITEM) getProcessAPI().getActivityInstance(id.toLong()); return convertEngineToConsoleItem(activityInstance); } catch (final ActivityInstanceNotFoundException e) { throw new APIItemNotFoundException(ActivityDefinition.TOKEN, id); } catch (final Exception e) { throw new APIException(e); } } @Override protected SearchResult<ENGINE_ITEM> runSearch(final SearchOptionsBuilder builder, final Map<String, String> filters) { try { @SuppressWarnings("unchecked") final SearchResult<ENGINE_ITEM> results = (SearchResult<ENGINE_ITEM>) getProcessAPI().searchActivities(builder.done()); return results; } catch (final Exception e) { throw new APIException(e); } } @Override protected SearchOptionsBuilder makeSearchOptionBuilder(final int page, final int resultsByPage, final String search, final String orders, final Map<String, String> filters) { return new SearchOptionsCreator(page, resultsByPage, search, new Sorts(orders, new ActivityAttributeConverter()), new Filters(filters, new ActivityFilterCreator())).getBuilder(); } @Override public CONSOLE_ITEM update(final APIID id, final Map<String, String> attributes) { final String jsonVariables = MapUtil.getValue(attributes, ActivityItem.ATTRIBUTE_VARIABLES, null); if (!isBlank(jsonVariables)) { updateActivityVariables(id.toLong(), jsonVariables); } update(get(id), attributes); try { return get(id); } catch (final APIException e) { if (e.getCause() instanceof ActivityInstanceNotFoundException) { return null; } throw e; } } private void updateActivityVariables(final long activityId, final String jsonValue) { final ActivityEngineClient activityEngineclient = getActivityEngineClient(); final HashMap<String, Serializable> variables = buildVariablesMap(activityId, jsonValue, activityEngineclient); activityEngineclient.updateVariables(activityId, variables); } private ActivityEngineClient getActivityEngineClient() { return new EngineClientFactory(new EngineAPIAccessor(getEngineSession())).createActivityEngineClient(); } private HashMap<String, Serializable> buildVariablesMap(final long activityId, final String jsonValue, final ActivityEngineClient client) { final HashMap<String, Serializable> map = new HashMap<String, Serializable>(); for (final VariableMapper var : VariablesMapper.fromJson(jsonValue).getVariables()) { final DataInstance data = client.getDataInstance(var.getName(), activityId); map.put(var.getName(), var.getSerializableValue(data.getClassName())); } return map; } protected void update(final CONSOLE_ITEM item, final Map<String, String> attributes) { updateState(item, MapUtil.getValue(attributes, FlowNodeItem.ATTRIBUTE_STATE, null), MapUtil.getValue(attributes, FlowNodeItem.ATTRIBUTE_EXECUTED_BY_USER_ID, null)); } /** * @param item * The item to update * @param state * The state to set */ protected void updateState(final CONSOLE_ITEM item, final String state, String userExecuteById) { try { if (state == null) { return; } if (HumanTaskItem.VALUE_STATE_SKIPPED.equals(state) && item instanceof FlowNodeItem) { getProcessAPI().setActivityStateByName(item.getId().toLong(), ActivityStates.SKIPPED_STATE); } else if (HumanTaskItem.VALUE_STATE_COMPLETED.equals(state) && item instanceof ActivityItem) { if (userExecuteById != null) { getProcessAPI().executeFlowNode(Long.valueOf(userExecuteById), item.getId().toLong()); } else { getProcessAPI().executeFlowNode(item.getId().toLong()); } } else { throw new APIException("Can't update " + item.getClass().getName() + " state to \"" + state + "\""); } } catch (final Exception e) { throw new APIException(e); } } }