| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.unomi.plugins.baseplugin.actions; |
| |
| import org.apache.commons.beanutils.PropertyUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.unomi.api.*; |
| import org.apache.unomi.api.actions.Action; |
| import org.apache.unomi.api.actions.ActionExecutor; |
| import org.apache.unomi.api.services.EventService; |
| import org.apache.unomi.persistence.spi.PropertyHelper; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| public class IncrementPropertyAction implements ActionExecutor { |
| private static final Logger logger = LoggerFactory.getLogger(IncrementPropertyAction.class.getName()); |
| |
| @Override |
| public int execute(final Action action, final Event event) { |
| boolean storeInSession = Boolean.TRUE.equals(action.getParameterValues().get("storeInSession")); |
| if (storeInSession && event.getSession() == null) { |
| return EventService.NO_CHANGE; |
| } |
| |
| String propertyName = (String) action.getParameterValues().get("propertyName"); |
| Profile profile = event.getProfile(); |
| Session session = event.getSession(); |
| |
| try { |
| Map<String, Object> properties = storeInSession ? session.getProperties() : profile.getProperties(); |
| Object propertyValue = getPropertyValue(action, event, propertyName, properties); |
| if (PropertyHelper.setProperty(properties, propertyName, propertyValue, "alwaysSet")) { |
| return storeInSession ? EventService.SESSION_UPDATED : EventService.PROFILE_UPDATED; |
| } |
| } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { |
| logger.warn("Error resolving nested property of object. See debug log level for more information"); |
| if (logger.isDebugEnabled()) { |
| logger.debug("Error resolving nested property of item: {}", storeInSession ? session : profile, e); |
| } |
| } catch (IllegalStateException ee) { |
| logger.warn("Error increment existing property, because existing property doesn't have expected type. See debug log level for more information"); |
| if (logger.isDebugEnabled()) { |
| logger.debug(ee.getMessage(), ee); |
| } |
| } |
| |
| return EventService.NO_CHANGE; |
| } |
| |
| private Object getPropertyValue(Action action, Event event, String propertyName, Map<String, Object> properties) |
| throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { |
| String propertyTarget = (String) action.getParameterValues().get("propertyTarget"); |
| String rootPropertyName = propertyName.split("\\.")[0]; |
| Object propertyValue = 1; |
| |
| Object propertyTargetValue = null; |
| |
| if (StringUtils.isNotEmpty(propertyTarget)) { |
| propertyTargetValue = PropertyUtils.getNestedProperty(((CustomItem) event.getTarget()).getProperties(), propertyTarget); |
| } |
| |
| if (propertyTargetValue != null) { |
| if (propertyTargetValue instanceof Integer) { |
| if (properties.containsKey(rootPropertyName)) { |
| Object nestedProperty = PropertyUtils.getNestedProperty(properties, propertyName); |
| if (nestedProperty == null) { |
| propertyValue = propertyTargetValue; |
| } else if (nestedProperty instanceof Integer) { |
| propertyValue = (int) propertyTargetValue + (int) nestedProperty; |
| } else { |
| throw new IllegalStateException("Property: " + propertyName + " already exist, can not increment the property because the exiting property is not integer"); |
| } |
| } else { |
| propertyValue = propertyTargetValue; |
| } |
| } else if (propertyTargetValue instanceof Map) { |
| if (properties.containsKey(rootPropertyName)) { |
| Object nestedPropertyValue = PropertyUtils.getNestedProperty(properties, propertyName); |
| if (nestedPropertyValue == null) { |
| propertyValue = propertyTargetValue; |
| } else if (nestedPropertyValue instanceof Map) { |
| // Create a new map to avoid modifying the original Object |
| Map<String, Object> newPropertyValue = new HashMap<>(); |
| Map<String, Object> nestedProperty = (Map<String, Object>) nestedPropertyValue; |
| |
| // increment with target |
| ((Map<String, Object>) propertyTargetValue).forEach((key, targetValue) -> { |
| if ((targetValue instanceof Integer && (nestedProperty.containsKey(key) && nestedProperty.get(key) instanceof Integer)) || |
| (targetValue instanceof Integer && !nestedProperty.containsKey(key))) { |
| newPropertyValue.put(key, nestedProperty.containsKey(key) ? (int) nestedProperty.get(key) + (int) targetValue : targetValue); |
| } |
| }); |
| |
| // add original props that was not incremented |
| nestedProperty.forEach((key, nestedValue) -> { |
| if (!newPropertyValue.containsKey(key)) { |
| newPropertyValue.put(key, nestedValue); |
| } |
| }); |
| propertyValue = newPropertyValue; |
| } else { |
| throw new IllegalStateException("Property: " + propertyName + " already exist, can not increment the properties from the map because the exiting property is not map"); |
| } |
| } else { |
| propertyValue = propertyTargetValue; |
| } |
| } |
| } else { |
| if (properties.containsKey(rootPropertyName)) { |
| Object nestedPropertyValue = PropertyUtils.getNestedProperty(properties, propertyName); |
| if (nestedPropertyValue == null) { |
| propertyValue = 1; |
| } else if (nestedPropertyValue instanceof Integer) { |
| propertyValue = (int) nestedPropertyValue + 1; |
| } else if (nestedPropertyValue instanceof Map) { |
| // Create a new map to avoid modifying the original object |
| Map<String, Object> newPropertyValue = new HashMap<>(); |
| Map<String, Object> nestedProperty = (Map<String, Object>) nestedPropertyValue; |
| nestedProperty.forEach((key, propValue) -> newPropertyValue.put(key, propValue instanceof Integer ? (int) propValue + 1 : propValue)); |
| propertyValue = newPropertyValue; |
| } else { |
| throw new IllegalStateException("Property: " + propertyName + " already exist, can not increment the property because the exiting property is not integer or map"); |
| } |
| } |
| } |
| |
| return propertyValue; |
| } |
| } |