http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java new file mode 100644 index 0000000..9a7c979 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java @@ -0,0 +1,200 @@ +/* + * 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.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Persona; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.Session; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.actions.ActionPostExecutor; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.services.DefinitionsService; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PersistenceService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.List; + +public class MergeProfilesOnPropertyAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(MergeProfilesOnPropertyAction.class.getName()); + + private final int MAX_COOKIE_AGE_IN_SECONDS = 60 * 60 * 24 * 365 * 10; // 10-years + private int cookieAgeInSeconds = MAX_COOKIE_AGE_IN_SECONDS; + private String profileIdCookieName = "context-profile-id"; + + private ProfileService profileService; + + private PersistenceService persistenceService; + + private EventService eventService; + + private DefinitionsService definitionsService; + + public void setCookieAgeInSeconds(int cookieAgeInSeconds) { + this.cookieAgeInSeconds = cookieAgeInSeconds; + } + + public void setProfileIdCookieName(String profileIdCookieName) { + this.profileIdCookieName = profileIdCookieName; + } + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + public PersistenceService getPersistenceService() { + return persistenceService; + } + + public void setPersistenceService(PersistenceService persistenceService) { + this.persistenceService = persistenceService; + } + + public EventService getEventService() { + return eventService; + } + + public void setEventService(EventService eventService) { + this.eventService = eventService; + } + + public DefinitionsService getDefinitionsService() { + return definitionsService; + } + + public void setDefinitionsService(DefinitionsService definitionsService) { + this.definitionsService = definitionsService; + } + + public int execute(Action action, Event event) { + + final Profile profile = event.getProfile(); + + final String mergeProfilePropertyName = (String) action.getParameterValues().get("mergeProfilePropertyName"); + final String mergeProfilePropertyValue = profile.getProperty(mergeProfilePropertyName) != null ? profile.getProperty(mergeProfilePropertyName).toString() : ""; + final Session currentSession = event.getSession(); + + // store the profile id in case the merge change it to a previous one + + if (profile instanceof Persona) { + return EventService.NO_CHANGE; + } + + if (StringUtils.isEmpty(mergeProfilePropertyValue)) { + return EventService.NO_CHANGE; + } + String profileId = profile.getItemId(); + + Condition propertyCondition = new Condition(definitionsService.getConditionType("eventPropertyCondition")); + propertyCondition.setParameter("comparisonOperator", "equals"); + propertyCondition.setParameter("propertyName", mergeProfilePropertyName); + propertyCondition.setParameter("propertyValue", mergeProfilePropertyValue); + + Condition excludeMergedProfilesCondition = new Condition(definitionsService.getConditionType("eventPropertyCondition")); + excludeMergedProfilesCondition.setParameter("comparisonOperator", "missing"); + excludeMergedProfilesCondition.setParameter("propertyName", "mergedWith"); + + Condition c = new Condition(definitionsService.getConditionType("booleanCondition")); + c.setParameter("operator", "and"); + c.setParameter("subConditions", Arrays.asList(propertyCondition, excludeMergedProfilesCondition)); + + final List<Profile> profiles = persistenceService.query(c, "properties.firstVisit", Profile.class); + + // add current Profile to profiles to be merged + boolean add = true; + for (Profile p : profiles) { + add = add && !StringUtils.equals(p.getItemId(), profile.getItemId()); + } + if (add) { + profiles.add(profile); + } + + if (profiles.size() == 1) { + return EventService.NO_CHANGE; + } + + Profile masterProfile = profileService.mergeProfiles(profiles.get(0), profiles); + + if (!masterProfile.getItemId().equals(profileId)) { + HttpServletResponse httpServletResponse = (HttpServletResponse) event.getAttributes().get(Event.HTTP_RESPONSE_ATTRIBUTE); + sendProfileCookie(event.getSession().getProfile(), httpServletResponse); + final String masterProfileId = masterProfile.getItemId(); + + // At the end of the merge, we must set the merged profile as profile event to process other Actions + event.setProfileId(masterProfileId); + event.setProfile(masterProfile); + + event.getActionPostExecutors().add(new ActionPostExecutor() { + @Override + public boolean execute() { + try { + for (Profile profile : profiles) { + String profileId = profile.getItemId(); + if (!StringUtils.equals(profileId, masterProfileId)) { + List<Session> sessions = persistenceService.query("profileId", profileId, null, Session.class); + if (currentSession.getProfileId().equals(profileId) && !sessions.contains(currentSession)) { + sessions.add(currentSession); + } + for (Session session : sessions) { + persistenceService.update(session.getItemId(), session.getTimeStamp(), Session.class, "profileId", masterProfileId); + } + + List<Event> events = persistenceService.query("profileId", profileId, null, Event.class); + for (Event event : events) { + persistenceService.update(event.getItemId(), event.getTimeStamp(), Event.class, "profileId", masterProfileId); + } + // we must mark all the profiles that we merged into the master as merged with the master, and they will + // be deleted upon next load + profile.setMergedWith(masterProfileId); + persistenceService.update(profile.getItemId(), null, Profile.class, "mergedWith", masterProfileId); + } + } + } catch (Exception e) { + logger.error("unable to execute callback action, profile and session will not be saved", e); + return false; + } + return true; + } + }); + return EventService.PROFILE_UPDATED; + } + + return EventService.NO_CHANGE; + } + + public void sendProfileCookie(Profile profile, ServletResponse response) { + if (response instanceof HttpServletResponse) { + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + Cookie profileIdCookie = new Cookie(profileIdCookieName, profile.getItemId()); + profileIdCookie.setPath("/"); + profileIdCookie.setMaxAge(cookieAgeInSeconds); + httpServletResponse.addCookie(profileIdCookie); + } + } + +}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SendEventAction.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SendEventAction.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SendEventAction.java new file mode 100644 index 0000000..f94851e --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SendEventAction.java @@ -0,0 +1,53 @@ +/* + * 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.unomi.api.Event; +import org.apache.unomi.api.Item; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; + +import java.util.Map; + +public class SendEventAction implements ActionExecutor { + + private EventService eventService; + + public void setEventService(EventService eventService) { + this.eventService = eventService; + } + + @Override + public int execute(Action action, Event event) { + String eventType = (String) action.getParameterValues().get("eventType"); + @SuppressWarnings("unchecked") + Map<String, Object> eventProperties = (Map<String, Object>) action.getParameterValues().get("eventProperties"); + Item target = (Item) action.getParameterValues().get("eventTarget"); +// String type = (String) target.get("type"); + +// Item targetItem = new CustomItem(); +// BeanUtils.populate(targetItem, target); + + Event subEvent = new Event(eventType, event.getSession(), event.getProfile(), event.getScope(), event, target, event.getTimeStamp()); + subEvent.getAttributes().putAll(event.getAttributes()); + subEvent.getProperties().putAll(eventProperties); + + return eventService.send(subEvent); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java new file mode 100644 index 0000000..7f5e31a --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java @@ -0,0 +1,87 @@ +/* + * 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.unomi.api.Event; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.services.DefinitionsService; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.persistence.spi.PersistenceService; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; + +public class SetEventOccurenceCountAction implements ActionExecutor { + private DefinitionsService definitionsService; + + private PersistenceService persistenceService; + + public void setDefinitionsService(DefinitionsService definitionsService) { + this.definitionsService = definitionsService; + } + + public void setPersistenceService(PersistenceService persistenceService) { + this.persistenceService = persistenceService; + } + + @Override + public int execute(Action action, Event event) { + final Condition pastEventCondition = (Condition) action.getParameterValues().get("pastEventCondition"); + + Condition andCondition = new Condition(definitionsService.getConditionType("booleanCondition")); + andCondition.setParameter("operator", "and"); + ArrayList<Condition> conditions = new ArrayList<Condition>(); + + Condition eventCondition = (Condition) pastEventCondition.getParameter("eventCondition"); + definitionsService.resolveConditionType(eventCondition); + conditions.add(eventCondition); + + Condition c = new Condition(definitionsService.getConditionType("eventPropertyCondition")); + c.setParameter("propertyName","profileId"); + c.setParameter("comparisonOperator", "equals"); + c.setParameter("propertyValue",event.getProfileId()); + conditions.add(c); + + if (pastEventCondition.getParameter("numberOfDays") != null) { + int i = (Integer) pastEventCondition.getParameter("numberOfDays"); + + Condition timeCondition = new Condition(definitionsService.getConditionType("eventPropertyCondition")); + timeCondition.setParameter("propertyName","timeStamp"); + timeCondition.setParameter("comparisonOperator","greaterThan"); + timeCondition.setParameter("propertyValueDateExpr","now-"+i+"d"); + + conditions.add(timeCondition); + } + + andCondition.setParameter("subConditions", conditions); + + long count = persistenceService.queryCount(andCondition, Event.ITEM_TYPE); + + Map<String,Object> pastEvents = (Map<String,Object>) event.getProfile().getSystemProperties().get("pastEvents"); + if (pastEvents == null) { + pastEvents = new LinkedHashMap<>(); + event.getProfile().getSystemProperties().put("pastEvents", pastEvents); + } + pastEvents.put((String) pastEventCondition.getParameter("generatedPropertyKey"), count + 1); + + return EventService.PROFILE_UPDATED; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetPropertyAction.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetPropertyAction.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetPropertyAction.java new file mode 100644 index 0000000..55c1210 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetPropertyAction.java @@ -0,0 +1,63 @@ +/* + * 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.unomi.api.Event; +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 java.text.SimpleDateFormat; +import java.util.TimeZone; + +public class SetPropertyAction implements ActionExecutor { + + public SetPropertyAction() { + } + + public String getActionId() { + return "setPropertyAction"; + } + + public int execute(Action action, Event event) { + Object propertyValue = action.getParameterValues().get("setPropertyValue"); + Object propertyValueInteger = action.getParameterValues().get("setPropertyValueInteger"); + + if(propertyValueInteger != null && propertyValue == null) { + propertyValue = PropertyHelper.getInteger(propertyValueInteger); + } + + if (propertyValue != null && propertyValue.equals("now")) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + propertyValue = format.format(event.getTimeStamp()); + } + String propertyName = (String) action.getParameterValues().get("setPropertyName"); + + boolean storeInSession = Boolean.TRUE.equals(action.getParameterValues().get("storeInSession")); + + Object target = storeInSession ? event.getSession() : event.getProfile(); + + if (PropertyHelper.setProperty(target, propertyName, propertyValue, (String) action.getParameterValues().get("setPropertyStrategy"))) { + return storeInSession ? EventService.SESSION_UPDATED : EventService.PROFILE_UPDATED; + } + return EventService.NO_CHANGE; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionESQueryBuilder.java new file mode 100644 index 0000000..919ce54 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionESQueryBuilder.java @@ -0,0 +1,54 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.List; +import java.util.Map; + +/** + * ES query builder for boolean conditions. + */ +public class BooleanConditionESQueryBuilder implements ConditionESQueryBuilder { + + @Override + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, + ConditionESQueryBuilderDispatcher dispatcher) { + boolean isAndOperator = "and".equalsIgnoreCase((String) condition.getParameter("operator")); + @SuppressWarnings("unchecked") + List<Condition> conditions = (List<Condition>) condition.getParameter("subConditions"); + + int conditionCount = conditions.size(); + + if (conditionCount == 1) { + return dispatcher.buildFilter(conditions.get(0), context); + } + + FilterBuilder[] l = new FilterBuilder[conditionCount]; + for (int i = 0; i < conditionCount; i++) { + l[i] = dispatcher.buildFilter(conditions.get(i), context); + } + + return isAndOperator ? FilterBuilders.andFilter(l) : FilterBuilders.orFilter(l); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionEvaluator.java new file mode 100644 index 0000000..1ecfc65 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/BooleanConditionEvaluator.java @@ -0,0 +1,51 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.Item; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; + +import java.util.List; +import java.util.Map; + +/** + * Evaluator for AND and OR conditions. + */ +public class BooleanConditionEvaluator implements ConditionEvaluator { + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, + ConditionEvaluatorDispatcher dispatcher) { + boolean isAnd = "and".equalsIgnoreCase((String) condition.getParameter("operator")); + @SuppressWarnings("unchecked") + List<Condition> conditions = (List<Condition>) condition.getParameter("subConditions"); + for (Condition sub : conditions) { + boolean eval = dispatcher.eval(sub, item, context); + if (!eval && isAnd) { + // And + return false; + } else if (eval && !isAnd) { + // Or + return true; + } + } + return isAnd; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionESQueryBuilder.java new file mode 100644 index 0000000..804f4f4 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionESQueryBuilder.java @@ -0,0 +1,60 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.Map; + +public class GeoLocationByPointSessionConditionESQueryBuilder implements ConditionESQueryBuilder { + @Override + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) { + String type = (String) condition.getParameter("type"); + + if("circle".equals(type)) { + Double circleLatitude = (Double) condition.getParameter("circleLatitude"); + Double circleLongitude = (Double) condition.getParameter("circleLongitude"); + String distance = condition.getParameter("distance").toString(); + + if(circleLatitude != null && circleLongitude != null && distance != null) { + return FilterBuilders.geoDistanceFilter("location") + .lat(circleLatitude) + .lon(circleLongitude) + .distance(distance); + } + } else if("rectangle".equals(type)) { + Double rectLatitudeNE = (Double) condition.getParameter("rectLatitudeNE"); + Double rectLongitudeNE = (Double) condition.getParameter("rectLongitudeNE"); + Double rectLatitudeSW = (Double) condition.getParameter("rectLatitudeSW"); + Double rectLongitudeSW = (Double) condition.getParameter("rectLongitudeSW"); + + if(rectLatitudeNE != null && rectLongitudeNE != null && rectLatitudeSW != null && rectLongitudeSW != null) { + return FilterBuilders.geoBoundingBoxFilter("location") + .topLeft(rectLatitudeNE, rectLongitudeNE) + .bottomRight(rectLatitudeSW, rectLongitudeSW); + } + } + + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionEvaluator.java new file mode 100644 index 0000000..c0b4134 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/GeoLocationByPointSessionConditionEvaluator.java @@ -0,0 +1,70 @@ +/* + * 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.conditions; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.unomi.api.Item; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; +import org.elasticsearch.common.geo.GeoDistance; +import org.elasticsearch.common.unit.DistanceUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class GeoLocationByPointSessionConditionEvaluator implements ConditionEvaluator { + + private static final Logger logger = LoggerFactory.getLogger(GeoLocationByPointSessionConditionEvaluator.class.getName()); + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) { + try { + String type = (String) condition.getParameter("type"); + Double latitudeProperty = Double.parseDouble(BeanUtils.getProperty(item, "properties.location.lat")); + Double longitudeProperty = Double.parseDouble(BeanUtils.getProperty(item, "properties.location.lon")); + + if("circle".equals(type)) { + Double circleLatitude = (Double) condition.getParameter("circleLatitude"); + Double circleLongitude = (Double) condition.getParameter("circleLongitude"); + DistanceUnit.Distance distance = DistanceUnit.Distance.parseDistance(condition.getParameter("distance").toString()); + + double d = GeoDistance.DEFAULT.calculate(circleLatitude, circleLongitude, latitudeProperty, longitudeProperty, distance.unit); + return d < distance.value; + } else if("rectangle".equals(type)) { + Double rectLatitudeNE = (Double) condition.getParameter("rectLatitudeNE"); + Double rectLongitudeNE = (Double) condition.getParameter("rectLongitudeNE"); + Double rectLatitudeSW = (Double) condition.getParameter("rectLatitudeSW"); + Double rectLongitudeSW = (Double) condition.getParameter("rectLongitudeSW"); + + if(rectLatitudeNE != null && rectLongitudeNE != null && rectLatitudeSW != null && rectLongitudeSW != null) { + return latitudeProperty < Math.max(rectLatitudeNE, rectLatitudeSW) && + latitudeProperty > Math.min(rectLatitudeNE, rectLatitudeSW) && + longitudeProperty < Math.max(rectLongitudeNE, rectLongitudeSW) && + longitudeProperty > Math.min(rectLongitudeNE, rectLongitudeSW); + } + } + } catch (Exception e) { + logger.debug("Cannot get properties", e); + } + return false; + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionESQueryBuilder.java new file mode 100644 index 0000000..9efd2c1 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionESQueryBuilder.java @@ -0,0 +1,34 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.Map; + +public class MatchAllConditionESQueryBuilder implements ConditionESQueryBuilder { + + @Override + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) { + return FilterBuilders.matchAllFilter(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionEvaluator.java new file mode 100644 index 0000000..ee8c1e8 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/MatchAllConditionEvaluator.java @@ -0,0 +1,33 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.Item; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; + +import java.util.Map; + +public class MatchAllConditionEvaluator implements ConditionEvaluator { + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) { + return true; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionESQueryBuilder.java new file mode 100644 index 0000000..7793aa0 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionESQueryBuilder.java @@ -0,0 +1,37 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.Map; + +/** + * Builder for NOT condition. + */ +public class NotConditionESQueryBuilder implements ConditionESQueryBuilder { + + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) { + Condition subCondition = (Condition) condition.getParameter("subCondition"); + return FilterBuilders.notFilter(dispatcher.buildFilter(subCondition, context)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionEvaluator.java new file mode 100644 index 0000000..5522f31 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NotConditionEvaluator.java @@ -0,0 +1,37 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.Item; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; + +import java.util.Map; + +/** + * Evaluator for NOT condition. + */ +public class NotConditionEvaluator implements ConditionEvaluator { + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) { + Condition subCondition = (Condition) condition.getParameter("subCondition"); + return !dispatcher.eval(subCondition, item, context); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java new file mode 100644 index 0000000..64fe15f --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java @@ -0,0 +1,88 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.services.DefinitionsService; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.apache.unomi.persistence.spi.PersistenceService; +import org.apache.unomi.persistence.spi.aggregate.TermsAggregate; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.*; + +public class PastEventConditionESQueryBuilder implements ConditionESQueryBuilder { + private DefinitionsService definitionsService; + private PersistenceService persistenceService; + + public void setDefinitionsService(DefinitionsService definitionsService) { + this.definitionsService = definitionsService; + } + + public void setPersistenceService(PersistenceService persistenceService) { + this.persistenceService = persistenceService; + } + + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) { + Condition eventCondition; + try { + eventCondition = (Condition) condition.getParameter("eventCondition"); + } catch (ClassCastException e) { + throw new IllegalArgumentException("Empty eventCondition"); + } + if (eventCondition == null) { + throw new IllegalArgumentException("No eventCondition"); + } + List<Condition> l = new ArrayList<Condition>(); + Condition andCondition = new Condition(); + andCondition.setConditionType(definitionsService.getConditionType("booleanCondition")); + andCondition.setParameter("operator", "and"); + andCondition.setParameter("subConditions", l); + + l.add(eventCondition); + + Integer numberOfDays = (Integer) condition.getParameter("numberOfDays"); + if (numberOfDays != null) { + Condition numberOfDaysCondition = new Condition(); + numberOfDaysCondition.setConditionType(definitionsService.getConditionType("sessionPropertyCondition")); + numberOfDaysCondition.setParameter("propertyName", "timeStamp"); + numberOfDaysCondition.setParameter("comparisonOperator", "greaterThan"); + numberOfDaysCondition.setParameter("propertyValueDateExpr", "now-" + numberOfDays + "d"); + l.add(numberOfDaysCondition); + } + //todo : Check behaviour with important number of profiles + Set<String> ids = new HashSet<String>(); + Integer minimumEventCount = condition.getParameter("minimumEventCount") == null ? 0 : (Integer) condition.getParameter("minimumEventCount"); + Integer maximumEventCount = condition.getParameter("maximumEventCount") == null ? Integer.MAX_VALUE : (Integer) condition.getParameter("maximumEventCount"); + + Map<String, Long> res = persistenceService.aggregateQuery(andCondition, new TermsAggregate("profileId"), Event.ITEM_TYPE); + for (Map.Entry<String, Long> entry : res.entrySet()) { + if (!entry.getKey().startsWith("_")) { + if (entry.getValue() >= minimumEventCount && entry.getValue() <= maximumEventCount) { + ids.add(entry.getKey()); + } + } + } + + return FilterBuilders.idsFilter(Profile.ITEM_TYPE).addIds(ids.toArray(new String[ids.size()])); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java new file mode 100644 index 0000000..0b18df5 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java @@ -0,0 +1,104 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Item; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.services.DefinitionsService; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; +import org.apache.unomi.persistence.spi.PersistenceService; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class PastEventConditionEvaluator implements ConditionEvaluator { + + private PersistenceService persistenceService; + + private DefinitionsService definitionsService; + + public void setPersistenceService(PersistenceService persistenceService) { + this.persistenceService = persistenceService; + } + + public void setDefinitionsService(DefinitionsService definitionsService) { + this.definitionsService = definitionsService; + } + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) { + + final Map<String, Object> parameters = condition.getParameterValues(); + + Condition eventCondition = (Condition) parameters.get("eventCondition"); + + long count; + + if (parameters.containsKey("generatedPropertyKey")) { + String key = (String) parameters.get("generatedPropertyKey"); + Profile profile = (Profile) item; + Map<String,Object> pastEvents = (Map<String, Object>) profile.getSystemProperties().get("pastEvents"); + if (pastEvents != null) { + Number l = (Number) pastEvents.get(key); + count = l != null ? l.longValue() : 0L; + } else { + count = 0; + } + + } else { + if (eventCondition == null) { + throw new IllegalArgumentException("No eventCondition"); + } + + List<Condition> l = new ArrayList<Condition>(); + Condition andCondition = new Condition(); + andCondition.setConditionType(definitionsService.getConditionType("booleanCondition")); + andCondition.setParameter("operator", "and"); + andCondition.setParameter("subConditions", l); + + l.add(eventCondition); + + Condition profileCondition = new Condition(); + profileCondition.setConditionType(definitionsService.getConditionType("sessionPropertyCondition")); + profileCondition.setParameter("propertyName", "profileId"); + profileCondition.setParameter("comparisonOperator", "equals"); + profileCondition.setParameter("propertyValue", item.getItemId()); + l.add(profileCondition); + + Integer numberOfDays = (Integer) condition.getParameter("numberOfDays"); + if (numberOfDays != null) { + Condition numberOfDaysCondition = new Condition(); + numberOfDaysCondition.setConditionType(definitionsService.getConditionType("sessionPropertyCondition")); + numberOfDaysCondition.setParameter("propertyName", "timeStamp"); + numberOfDaysCondition.setParameter("comparisonOperator", "greaterThan"); + numberOfDaysCondition.setParameter("propertyValueDateExpr", "now-" + numberOfDays + "d"); + l.add(numberOfDaysCondition); + } + count = persistenceService.queryCount(andCondition, Event.ITEM_TYPE); + } + + Integer minimumEventCount = parameters.get("minimumEventCount") == null ? 0 : (Integer) parameters.get("minimumEventCount"); + Integer maximumEventCount = parameters.get("maximumEventCount") == null ? Integer.MAX_VALUE : (Integer) parameters.get("maximumEventCount"); + + return count > 0 && (count >= minimumEventCount && count <= maximumEventCount); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java new file mode 100644 index 0000000..d063ff3 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java @@ -0,0 +1,135 @@ +/* + * 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.conditions; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionContextHelper; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.List; +import java.util.Map; + +public class PropertyConditionESQueryBuilder implements ConditionESQueryBuilder { + + public PropertyConditionESQueryBuilder() { + } + + @Override + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) { + String op = (String) condition.getParameter("comparisonOperator"); + String name = (String) condition.getParameter("propertyName"); + + if(op == null || name == null){ + throw new IllegalArgumentException("Impossible to build ES filter, condition is not valid, comparisonOperator and propertyName properties should be provided"); + } + + String expectedValue = ConditionContextHelper.foldToASCII((String) condition.getParameter("propertyValue")); + Object expectedValueInteger = condition.getParameter("propertyValueInteger"); + Object expectedValueDate = condition.getParameter("propertyValueDate"); + Object expectedValueDateExpr = condition.getParameter("propertyValueDateExpr"); + + List<?> expectedValues = ConditionContextHelper.foldToASCII((List<?>) condition.getParameter("propertyValues")); + List<?> expectedValuesInteger = (List<?>) condition.getParameter("propertyValuesInteger"); + List<?> expectedValuesDate = (List<?>) condition.getParameter("propertyValuesDate"); + List<?> expectedValuesDateExpr = (List<?>) condition.getParameter("propertyValuesDateExpr"); + + Object value = ObjectUtils.firstNonNull(expectedValue,expectedValueInteger,expectedValueDate,expectedValueDateExpr); + @SuppressWarnings("unchecked") + List<?> values = ObjectUtils.firstNonNull(expectedValues,expectedValuesInteger,expectedValuesDate,expectedValuesDateExpr); + + switch (op) { + case "equals": + checkRequiredValue(value, name, op, false); + return FilterBuilders.termFilter(name, value); + case "notEquals": + checkRequiredValue(value, name, op, false); + return FilterBuilders.notFilter(FilterBuilders.termFilter(name, value)); + case "greaterThan": + checkRequiredValue(value, name, op, false); + return FilterBuilders.rangeFilter(name).gt(value); + case "greaterThanOrEqualTo": + checkRequiredValue(value, name, op, false); + return FilterBuilders.rangeFilter(name).gte(value); + case "lessThan": + checkRequiredValue(value, name, op, false); + return FilterBuilders.rangeFilter(name).lt(value); + case "lessThanOrEqualTo": + checkRequiredValue(value, name, op, false); + return FilterBuilders.rangeFilter(name).lte(value); + case "between": + checkRequiredValuesSize(values, name, op, 2); + return FilterBuilders.rangeFilter(name).gte(values.get(0)).lte(values.get(1)); + case "exists": + return FilterBuilders.existsFilter(name); + case "missing": + return FilterBuilders.missingFilter(name); + case "contains": + checkRequiredValue(expectedValue, name, op, false); + return FilterBuilders.regexpFilter(name, ".*" + expectedValue + ".*"); + case "startsWith": + checkRequiredValue(expectedValue, name, op, false); + return FilterBuilders.prefixFilter(name, expectedValue); + case "endsWith": + checkRequiredValue(expectedValue, name, op, false); + return FilterBuilders.regexpFilter(name, ".*" + expectedValue); + case "matchesRegex": + checkRequiredValue(expectedValue, name, op, false); + return FilterBuilders.regexpFilter(name, expectedValue); + case "in": + checkRequiredValue(values, name, op, true); + return FilterBuilders.inFilter(name, values.toArray()); + case "notIn": + checkRequiredValue(values, name, op, true); + return FilterBuilders.notFilter(FilterBuilders.inFilter(name, values.toArray())); + case "all": + checkRequiredValue(values, name, op, true); + return FilterBuilders.termsFilter(name, values.toArray()).execution("and"); + case "isDay": + checkRequiredValue(value, name, op, false); + return getIsSameDayRange(value, name); + case "isNotDay": + checkRequiredValue(value, name, op, false); + return FilterBuilders.notFilter(getIsSameDayRange(value, name)); + } + return null; + } + + private void checkRequiredValuesSize(List<?> values, String name, String operator, int expectedSize) { + if(values == null || values.size() != expectedSize) { + throw new IllegalArgumentException("Impossible to build ES filter, missing " + expectedSize + " values for a condition using comparisonOperator: " + operator + ", and propertyName: " + name); + } + } + + private void checkRequiredValue(Object value, String name, String operator, boolean multiple) { + if(value == null) { + throw new IllegalArgumentException("Impossible to build ES filter, missing value" + (multiple ? "s" : "") + " for condition using comparisonOperator: " + operator + ", and propertyName: " + name); + } + } + + private FilterBuilder getIsSameDayRange (Object value, String name) { + DateTime date = new DateTime(value); + DateTime dayStart = date.withTimeAtStartOfDay(); + DateTime dayAfterStart = date.plusDays(1).withTimeAtStartOfDay(); + return FilterBuilders.rangeFilter(name).gte(dayStart.toDate()).lte(dayAfterStart.toDate()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java new file mode 100644 index 0000000..ca3e512 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java @@ -0,0 +1,299 @@ +/* + * 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.conditions; + +import ognl.Node; +import ognl.Ognl; +import ognl.OgnlContext; +import ognl.OgnlException; +import ognl.enhance.ExpressionAccessor; +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Item; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionContextHelper; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.joda.DateMathParser; +import org.elasticsearch.index.mapper.core.DateFieldMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +/** + * Evaluator for property comparison conditions + */ +public class PropertyConditionEvaluator implements ConditionEvaluator { + + private static final Logger logger = LoggerFactory.getLogger(PropertyConditionEvaluator.class.getName()); + + private static final SimpleDateFormat yearMonthDayDateFormat = new SimpleDateFormat("yyyyMMdd"); + + private BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance(); + + private Map<String, Map<String, ExpressionAccessor>> expressionCache = new HashMap<>(64); + + private int compare(Object actualValue, String expectedValue, Object expectedValueDate, Object expectedValueInteger, Object expectedValueDateExpr) { + if (expectedValue == null && expectedValueDate == null && expectedValueInteger == null && getDate(expectedValueDateExpr) == null) { + return actualValue == null ? 0 : 1; + } else if (actualValue == null) { + return -1; + } + + if (expectedValueInteger != null) { + return PropertyHelper.getInteger(actualValue).compareTo(PropertyHelper.getInteger(expectedValueInteger)); + } else if (expectedValueDate != null) { + return getDate(actualValue).compareTo(getDate(expectedValueDate)); + } else if (expectedValueDateExpr != null) { + return getDate(actualValue).compareTo(getDate(expectedValueDateExpr)); + } else { + return actualValue.toString().compareTo(expectedValue); + } + } + + private boolean compareMultivalue(Object actualValue, List<?> expectedValues, List<?> expectedValuesDate, List<?> expectedValuesNumber, List<?> expectedValuesDateExpr, String op) { + @SuppressWarnings("unchecked") + List<?> expected = ObjectUtils.firstNonNull(expectedValues, expectedValuesDate, expectedValuesNumber); + if (actualValue == null) { + return expected == null; + } else if (expected == null) { + return false; + } + + List<Object> actual = ConditionContextHelper.foldToASCII(getValueSet(actualValue)); + + boolean result = true; + + switch (op) { + case "in": + result = false; + for (Object a : actual) { + if (expected.contains(a)) { + result = true; + break; + } + } + break; + case "notIn": + for (Object a : actual) { + if (expected.contains(a)) { + result = false; + break; + } + } + break; + case "all": + for (Object e : expected) { + if (!actual.contains(e)) { + result = false; + break; + } + } + break; + + default: + throw new IllegalArgumentException("Unknown comparison operator " + op); + } + + return result; + } + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) { + String op = (String) condition.getParameter("comparisonOperator"); + String name = (String) condition.getParameter("propertyName"); + + String expectedValue = ConditionContextHelper.foldToASCII((String) condition.getParameter("propertyValue")); + Object expectedValueInteger = condition.getParameter("propertyValueInteger"); + Object expectedValueDate = condition.getParameter("propertyValueDate"); + Object expectedValueDateExpr = condition.getParameter("propertyValueDateExpr"); + + Object actualValue; + if (item instanceof Event && "eventType".equals(name)) { + actualValue = ((Event)item).getEventType(); + } else { + try { + long time = System.nanoTime(); + //actualValue = beanUtilsBean.getPropertyUtils().getProperty(item, name); + actualValue = getPropertyValue(item, name); + time = System.nanoTime() - time; + if (time > 5000000L) { + logger.info("eval took {} ms for {} {}", time / 1000000L, item.getClass().getName(), name); + } + } catch (NullPointerException e) { + // property not found + actualValue = null; + } catch (Exception e) { + if (!(e instanceof OgnlException) + || (!StringUtils.startsWith(e.getMessage(), + "source is null for getProperty(null"))) { + logger.warn("Error evaluating value for " + item.getClass().getName() + " " + name, e); + } + actualValue = null; + } + } + if (actualValue instanceof String) { + actualValue = ConditionContextHelper.foldToASCII((String) actualValue); + } + + if(op == null) { + return false; + } else if(actualValue == null){ + return op.equals("missing"); + } else if (op.equals("exists")) { + return true; + } else if (op.equals("equals")) { + if (actualValue instanceof Collection) { + for (Object o : ((Collection<?>)actualValue)) { + if (o instanceof String) { + o = ConditionContextHelper.foldToASCII((String) o); + } + if (compare(o, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) == 0) { + return true; + } + } + return false; + } + return compare(actualValue, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) == 0; + } else if (op.equals("notEquals")) { + return compare(actualValue, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) != 0; + } else if (op.equals("greaterThan")) { + return compare(actualValue, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) > 0; + } else if (op.equals("greaterThanOrEqualTo")) { + return compare(actualValue, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) >= 0; + } else if (op.equals("lessThan")) { + return compare(actualValue, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) < 0; + } else if (op.equals("lessThanOrEqualTo")) { + return compare(actualValue, expectedValue, expectedValueDate, expectedValueInteger, expectedValueDateExpr) <= 0; + } else if (op.equals("between")) { + List<?> expectedValuesInteger = (List<?>) condition.getParameter("propertyValuesInteger"); + List<?> expectedValuesDate = (List<?>) condition.getParameter("propertyValuesDate"); + List<?> expectedValuesDateExpr = (List<?>) condition.getParameter("propertyValuesDateExpr"); + return compare(actualValue, null, + (expectedValuesDate != null && expectedValuesDate.size() >= 1) ? getDate(expectedValuesDate.get(0)) : null, + (expectedValuesInteger != null && expectedValuesInteger.size() >= 1) ? (Integer) expectedValuesInteger.get(0) : null, + (expectedValuesDateExpr != null && expectedValuesDateExpr.size() >= 1) ? (String) expectedValuesDateExpr.get(0) : null) >= 0 + && + compare(actualValue, null, + (expectedValuesDate != null && expectedValuesDate.size() >= 2) ? getDate(expectedValuesDate.get(1)) : null, + (expectedValuesInteger != null && expectedValuesInteger.size() >= 2) ? (Integer) expectedValuesInteger.get(1) : null, + (expectedValuesDateExpr != null && expectedValuesDateExpr.size() >= 2) ? (String) expectedValuesDateExpr.get(1) : null) <= 0; + } else if (op.equals("contains")) { + return actualValue.toString().contains(expectedValue); + } else if (op.equals("startsWith")) { + return actualValue.toString().startsWith(expectedValue); + } else if (op.equals("endsWith")) { + return actualValue.toString().endsWith(expectedValue); + } else if (op.equals("matchesRegex")) { + return expectedValue != null && Pattern.compile(expectedValue).matcher(actualValue.toString()).matches(); + } else if (op.equals("in") || op.equals("notIn") || op.equals("all")) { + List<?> expectedValues = ConditionContextHelper.foldToASCII((List<?>) condition.getParameter("propertyValues")); + List<?> expectedValuesInteger = (List<?>) condition.getParameter("propertyValuesInteger"); + List<?> expectedValuesDate = (List<?>) condition.getParameter("propertyValuesDate"); + List<?> expectedValuesDateExpr = (List<?>) condition.getParameter("propertyValuesDateExpr"); + + return compareMultivalue(actualValue, expectedValues, expectedValuesDate, expectedValuesInteger, expectedValuesDateExpr, op); + } else if(op.equals("isDay") && expectedValueDate != null) { + return yearMonthDayDateFormat.format(getDate(actualValue)).equals(yearMonthDayDateFormat.format(getDate(expectedValueDate))); + } else if(op.equals("isNotDay") && expectedValueDate != null) { + return !yearMonthDayDateFormat.format(getDate(actualValue)).equals(yearMonthDayDateFormat.format(getDate(expectedValueDate))); + } + + return false; + } + + private Object getPropertyValue(Item item, String expression) throws Exception { + ExpressionAccessor accessor = getPropertyAccessor(item, expression); + return accessor != null ? accessor.get((OgnlContext) Ognl.createDefaultContext(null), item) : null; + } + + private ExpressionAccessor getPropertyAccessor(Item item, String expression) throws Exception { + ExpressionAccessor accessor = null; + String clazz = item.getClass().getName(); + Map<String, ExpressionAccessor> expressions = expressionCache.get(clazz); + if (expressions == null) { + expressions = new HashMap<>(); + expressionCache.put(clazz, expressions); + } else { + accessor = expressions.get(expression); + } + if (accessor == null) { + long time = System.nanoTime(); + Thread current = Thread.currentThread(); + ClassLoader contextCL = current.getContextClassLoader(); + try { + current.setContextClassLoader(PropertyConditionEvaluator.class.getClassLoader()); + Node node = Ognl.compileExpression((OgnlContext) Ognl.createDefaultContext(null), item, expression); + accessor = node.getAccessor(); + } finally { + current.setContextClassLoader(contextCL); + } + if (accessor != null) { + expressions.put(expression, accessor); + } else { + logger.warn("Unable to compile expression for {} and {}", clazz, expression); + } + time = System.nanoTime() - time; + logger.info("Expression compilation for {} took {}", expression, time / 1000000L); + } + + return accessor; + } + + private Date getDate(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date) { + return ((Date) value); + } else { + DateMathParser parser = new DateMathParser(DateFieldMapper.Defaults.DATE_TIME_FORMATTER, TimeUnit.MILLISECONDS); + try { + return new Date(parser.parse(value.toString(), new Callable<Long>() { + @Override + public Long call() throws Exception { + return System.currentTimeMillis(); + } + })); + } catch (ElasticsearchParseException e) { + logger.warn("unable to parse date " + value.toString(), e); + } + } + return null; + } + + @SuppressWarnings("unchecked") + private List<Object> getValueSet(Object expectedValue) { + if (expectedValue instanceof List) { + return (List<Object>) expectedValue; + } else if (expectedValue instanceof Collection) { + return new ArrayList<Object>((Collection<?>) expectedValue); + } else { + return Collections.singletonList(expectedValue); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionESQueryBuilder.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionESQueryBuilder.java new file mode 100644 index 0000000..68e5944 --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionESQueryBuilder.java @@ -0,0 +1,54 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher; +import org.elasticsearch.index.query.FilterBuilder; +import org.elasticsearch.index.query.FilterBuilders; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class SourceEventPropertyConditionESQueryBuilder implements ConditionESQueryBuilder { + + public SourceEventPropertyConditionESQueryBuilder() { + } + + private void appendFilderIfPropExist(List<FilterBuilder> filterBuilders, Condition condition, String prop){ + final Object parameter = condition.getParameter(prop); + if (parameter != null && !"".equals(parameter)) { + filterBuilders.add(FilterBuilders.termFilter("source." + prop, (String) parameter)); + } + } + + public FilterBuilder buildFilter(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) { + List<FilterBuilder> l = new ArrayList<FilterBuilder>(); + for (String prop : new String[]{"id", "path", "scope", "type"}){ + appendFilderIfPropExist(l, condition, prop); + } + + if (l.size() >= 1) { + return l.size() == 1 ? l.get(0) : FilterBuilders.andFilter(l.toArray(new FilterBuilder[l.size()])); + } else { + return null; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionEvaluator.java new file mode 100644 index 0000000..98669dd --- /dev/null +++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/SourceEventPropertyConditionEvaluator.java @@ -0,0 +1,80 @@ +/* + * 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.conditions; + +import org.apache.unomi.api.Item; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.conditions.ConditionType; +import org.apache.unomi.api.services.DefinitionsService; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator; +import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SourceEventPropertyConditionEvaluator implements ConditionEvaluator { + private static final Map<String,String> MAPPED_PROPERTIES; + static { + MAPPED_PROPERTIES = new HashMap<>(4); + MAPPED_PROPERTIES.put("id", "itemId"); + MAPPED_PROPERTIES.put("path", "properties.pageInfo.pagePath"); + MAPPED_PROPERTIES.put("type", "itemType"); + MAPPED_PROPERTIES.put("scope", "scope"); + } + + private DefinitionsService definitionsService; + + private void appendConditionIfPropExist(List<Condition> conditions, Condition condition, String prop, ConditionType propConditionType) { + final Object parameter = condition.getParameter(prop); + if (parameter != null && !"".equals(parameter)) { + Condition propCondition = new Condition(propConditionType); + propCondition.setParameter("comparisonOperator", "equals"); + propCondition.setParameter("propertyName",MAPPED_PROPERTIES.get(prop)); + propCondition.setParameter("propertyValue", parameter); + conditions.add(propCondition); + } + } + + @Override + public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) { + Condition andCondition = new Condition(definitionsService.getConditionType("booleanCondition")); + andCondition.setParameter("operator", "and"); + ArrayList<Condition> conditions = new ArrayList<Condition>(); + + for (String prop : MAPPED_PROPERTIES.keySet()){ + appendConditionIfPropExist(conditions, condition, prop, definitionsService.getConditionType("eventPropertyCondition")); + } + + if(conditions.size() > 0){ + andCondition.setParameter("subConditions", conditions); + return dispatcher.eval(andCondition, item); + } else { + return true; + } + } + + public DefinitionsService getDefinitionsService() { + return definitionsService; + } + + public void setDefinitionsService(DefinitionsService definitionsService) { + this.definitionsService = definitionsService; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/plugins/baseplugin/src/main/java/org/oasis_open/contextserver/plugins/baseplugin/actions/AllEventToProfilePropertiesAction.java ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/java/org/oasis_open/contextserver/plugins/baseplugin/actions/AllEventToProfilePropertiesAction.java b/plugins/baseplugin/src/main/java/org/oasis_open/contextserver/plugins/baseplugin/actions/AllEventToProfilePropertiesAction.java deleted file mode 100644 index d50c32d..0000000 --- a/plugins/baseplugin/src/main/java/org/oasis_open/contextserver/plugins/baseplugin/actions/AllEventToProfilePropertiesAction.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.oasis_open.contextserver.plugins.baseplugin.actions; - -import org.apache.commons.beanutils.BeanUtilsBean; -import org.oasis_open.contextserver.api.Event; -import org.oasis_open.contextserver.api.actions.Action; -import org.oasis_open.contextserver.api.actions.ActionExecutor; -import org.oasis_open.contextserver.api.services.EventService; -import org.oasis_open.contextserver.api.services.ProfileService; - -import java.util.HashMap; -import java.util.Map; - -public class AllEventToProfilePropertiesAction implements ActionExecutor { - - private ProfileService profileService; - - public void setProfileService(ProfileService profileService) { - this.profileService = profileService; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public int execute(Action action, Event event) { - boolean changed = false; - Map<String, Object> properties = new HashMap<String,Object>(); - if (event.getProperties() != null) { - properties.putAll(event.getProperties()); - } - - - try { - Object targetProperties = BeanUtilsBean.getInstance().getPropertyUtils().getProperty(event.getTarget(), "properties"); - if (targetProperties instanceof Map) { - properties.putAll( (Map)targetProperties ); - } - } catch (Exception e) { - // Ignore - } - for (Map.Entry<String, Object> entry : properties.entrySet()) { - if (event.getProfile().getProperty(entry.getKey()) == null || !event.getProfile().getProperty(entry.getKey()).equals(event.getProperty(entry.getKey()))) { - String propertyMapping = profileService.getPropertyTypeMapping(entry.getKey()); - if (propertyMapping != null) { - event.getProfile().setProperty(propertyMapping, entry.getValue()); - } else { - event.getProfile().setProperty(entry.getKey(), entry.getValue()); - } - changed = true; - } - } - return changed ? EventService.PROFILE_UPDATED : EventService.NO_CHANGE; - } -}
