com.ericsson.deviceaccess.adaptor.ruleengine.device.Rule.java Source code

Java tutorial

Introduction

Here is the source code for com.ericsson.deviceaccess.adaptor.ruleengine.device.Rule.java

Source

/*
 * Copyright Ericsson AB 2011-2014. All Rights Reserved.
 *
 * The contents of this file are subject to the Lesser GNU Public License,
 *  (the "License"), either version 2.1 of the License, or
 * (at your option) any later version.; you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * License along with this software. If not, it can be
 * retrieved online at https://www.gnu.org/licenses/lgpl.html. Moreover
 * it could also be requested from Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
 * WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
 * EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
 * OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND,
    
 * EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
 * LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE,
 * YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 *
 * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 * REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
 * DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
 * DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
 * (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
 * INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE
 * OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH
 * HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 */
package com.ericsson.deviceaccess.adaptor.ruleengine.device;

import com.ericsson.common.util.function.FunctionalUtil;
import com.ericsson.deviceaccess.adaptor.ruleengine.Activator;
import com.ericsson.deviceaccess.api.Constants;
import com.ericsson.deviceaccess.api.GenericDevice;
import com.ericsson.deviceaccess.api.genericdevice.GDAction;
import com.ericsson.deviceaccess.api.genericdevice.GDException;
import com.ericsson.deviceaccess.api.genericdevice.GDProperties;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

public class Rule {

    final static Map<String, Integer> WEEKDAYS = new HashMap<String, Integer>() {
        {
            put("sun", 0);
            put("mon", 1);
            put("tue", 2);
            put("wed", 3);
            put("thu", 4);
            put("fri", 5);
            put("sat", 6);
        }
    };
    private final String id;
    private final String name;
    private String conditions;
    private String startTime;
    private float startTimeFloat;
    private String stopTime;
    private float stopTimeFloat;
    private String weekDays;
    private boolean[] weekDaysBool;
    private List<RuleAction> actionsThen;
    private List<RuleAction> actionsElse;
    private List<RuleAction> actionsStart;
    private List<RuleAction> actionsStop;
    LDAPExpr ldapFilter;
    private Timer timer = null;
    private boolean started = false;

    public Rule(String id, RuleInfo info) {
        this.id = id;
        this.name = info.name;
        this.conditions = info.conditions;
        setStartTime(info.startTime);
        setStopTime(info.stopTime);
        setWeekDays(info.weekDays);
        try {
            setActionsThen(info.actionsThen);
            setActionsElse(info.actionsElse);
            setActionsStart(info.actionsStart);
            setActionsStop(info.actionsStop);
        } catch (JSONException ex) {
            throw new IllegalArgumentException(ex);
        }
        try {
            ldapFilter = new LDAPExpr(conditions);
        } catch (InvalidSyntaxException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    public Rule start() {
        schedule();
        started = true;
        return this;
    }

    public void stop() {
        started = false;
        unschedule();
    }

    public void setConditions(String conditions) throws InvalidSyntaxException {
        this.conditions = conditions;
        ldapFilter = new LDAPExpr(conditions);
    }

    protected LDAPExpr getLDAPFilter() {
        return ldapFilter;
    }

    public String getConditions() {
        return conditions;
    }

    public final void setStartTime(String startTime) {
        if (startTime.trim().isEmpty()) {
            return;
        }

        int idx = startTime.indexOf(':');
        if (idx <= 0) {
            throw new IllegalArgumentException("Illegal start time"); // TODO: Allow this if empty
        }
        int hours = Integer.parseInt(startTime.substring(0, idx));
        int minutes = Integer.parseInt(startTime.substring(idx + 1));
        startTimeFloat = hours + ((float) minutes) / 60;

        this.startTime = startTime;
    }

    public final void setStopTime(String stopTime) {
        if (stopTime.trim().isEmpty()) {
            return;
        }

        int idx = stopTime.indexOf(':');
        if (idx <= 0) {
            throw new IllegalArgumentException("Illegal stop time");
        }

        int hours = Integer.parseInt(stopTime.substring(0, idx));
        int minutes = Integer.parseInt(stopTime.substring(idx + 1));
        stopTimeFloat = hours + ((float) minutes) / 60;

        this.stopTime = stopTime;
    }

    public final void setWeekDays(String weekDays) {
        weekDaysBool = new boolean[7];

        StringTokenizer st = new StringTokenizer(weekDays, ",");
        while (st.hasMoreElements()) {
            String weekDay = st.nextToken().trim();
            Integer weekDayIdx = WEEKDAYS.get(weekDay);
            if (weekDayIdx == null) {
                throw new IllegalArgumentException("Invalid weekday: " + weekDay);
            }

            weekDaysBool[weekDayIdx] = true;
        }

        this.weekDays = weekDays;
    }

    private List<RuleAction> createRuleActions(String actions) throws JSONException {
        List<RuleAction> actionsList = new LinkedList<>();
        if (actions.trim().isEmpty()) {
            return actionsList;
        }

        JSONArray json = new JSONArray(actions);
        for (int i = 0; i < json.length(); i++) {
            JSONObject action = json.getJSONObject(i);
            RuleAction ruleAction = new RuleAction();
            ruleAction.setDeviceId(action.getString("id"));
            ruleAction.setServiceName(action.getString("service"));
            ruleAction.setActionName(action.getString("action"));
            JSONArray args = action.getJSONArray("args");
            HashMap<String, String> arguments = new HashMap<>();
            for (int j = 0; j < args.length(); j++) {
                JSONObject arg = args.getJSONObject(j);
                String argName = (String) arg.keys().next();
                arguments.put(argName, arg.getString(argName));
            }
            ruleAction.setArguments(arguments);
            actionsList.add(ruleAction);
        }

        return actionsList;
    }

    public final void setActionsThen(String actionsThen) throws JSONException {
        this.actionsThen = createRuleActions(actionsThen);
    }

    public final void setActionsElse(String actionsElse) throws JSONException {
        this.actionsElse = createRuleActions(actionsElse);
    }

    public final void setActionsStart(String actionsStart) throws JSONException {
        this.actionsStart = createRuleActions(actionsStart);
    }

    public final void setActionsStop(String actionsStop) throws JSONException {
        this.actionsStop = createRuleActions(actionsStop);
    }

    public boolean checkTimeOfDay() {
        Calendar date = Calendar.getInstance();
        int hourOfDay = date.get(Calendar.HOUR_OF_DAY);
        //Removed casting
        int minute = date.get(Calendar.MINUTE);
        float time = hourOfDay + minute / 60;

        if (startTimeFloat < stopTimeFloat) {
            return time >= startTimeFloat && time < stopTimeFloat;
        } else {
            if (time >= startTimeFloat) {
                return true;
            } else if (time < stopTimeFloat) {
                return true;
            }
        }

        return false;
    }

    public boolean checkWeekDay() {
        Calendar date = Calendar.getInstance();
        int day = date.get(Calendar.DAY_OF_WEEK);
        return weekDaysBool[day - 1];
    }

    private void invokeActions(List<RuleAction> actions) {
        actions.stream().forEach(ruleAction -> {
            GenericDevice device = getDevice(ruleAction.getDeviceId());
            if (device != null) {
                GDAction action = device.getService(ruleAction.getServiceName())
                        .getAction(ruleAction.getActionName());
                GDProperties args = action.createArguments();
                ruleAction.getArguments().forEach((argName, value) -> {
                    args.setStringValue(argName, value);
                });

                try {
                    action.execute(args);
                } catch (GDException e) {
                }
            }
        });
    }

    private GenericDevice getDevice(String deviceId) {
        try {
            String idFilter = "(" + Constants.PARAM_DEVICE_ID + "=" + deviceId + ")";
            ServiceReference[] refs = Activator.context.getAllServiceReferences(GenericDevice.class.getName(),
                    idFilter);
            if (refs != null) {
                for (ServiceReference ref : refs) {
                    GenericDevice dev = (GenericDevice) Activator.context.getService(ref);
                    if (deviceId.equals(dev.getId())) {
                        return dev;
                    }
                }
            }
        } catch (InvalidSyntaxException e) {
            e.printStackTrace();
        }

        return null;
    }

    public void invokeThen() {
        if (!checkWeekDay() || !checkTimeOfDay()) {
            return;
        }
        System.out.println("Invoking Then for rule " + name + ", " + new Date());
        invokeActions(actionsThen);
    }

    public void invokeElse() {
        if (!checkWeekDay() || !checkTimeOfDay()) {
            return;
        }
        System.out.println("Invoking Else for rule " + name + ", " + new Date());
        invokeActions(actionsElse);
    }

    public void invokeStart() {
        if (!checkWeekDay()) {
            return;
        }
        System.out.println("Invoking Start for rule " + name + ", " + new Date());
        invokeActions(actionsStart);
    }

    public void invokeStop() {
        // TODO: If stopTime is after midnight we should allow it if the previous weekday is enabled
        if (!checkWeekDay()) {
            return;
        }
        System.out.println("Invoking Stop for rule " + name + ", " + new Date());
        invokeActions(actionsStop);
    }

    public String getName() {
        return name;
    }

    public List<String> getFilterAttributeNames() {
        return getLDAPFilter().getAttributeNames();
    }

    public void schedule() {
        unschedule();
        timer = new Timer();

        if (startTime != null && !startTime.trim().isEmpty()) {
            callTimer(startTime, Condition.START);
        } else if (stopTime != null && !stopTime.trim().isEmpty()) {
            callTimer(stopTime, Condition.STOP);
        }
    }

    private void callTimer(String time, Condition condition) {
        try {
            int idx = time.indexOf(':');
            if (idx <= 0) {
                throw new Exception("Illegal " + condition + " time");
            }

            int hours = Integer.parseInt(time.substring(0, idx));
            int minutes = Integer.parseInt(time.substring(idx + 1));
            Calendar date = Calendar.getInstance();
            date.set(Calendar.HOUR_OF_DAY, hours);
            date.set(Calendar.MINUTE, minutes);
            date.set(Calendar.SECOND, 1);
            Date triggerDate = date.getTime();
            if (triggerDate.getTime() <= new Date().getTime()) {
                triggerDate = new Date(triggerDate.getTime() + 24 * 3600000);
            }
            System.out.println(triggerDate);
            TimerTask task = FunctionalUtil.timerTask(() -> {
                if (ldapFilter.evaluate(PropertyManager.INSTANCE.getDeviceProperties(), true)) {
                    switch (condition) {
                    case START:
                        invokeStart();
                        break;
                    case STOP:
                        invokeStop();
                        break;
                    }
                }
            });
            timer.scheduleAtFixedRate(task, triggerDate, 24 * 3600000);
        } catch (Exception e) {
        }
    }

    private void unschedule() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    public boolean match(Map<String, Object> properties) {
        return ldapFilter.evaluate(properties, true);
    }

    @Override
    public String toString() {
        return "Rule: " + name;
    }

    private static enum Condition {

        START, STOP;
    }

    public static class RuleInfo {

        String name;
        String conditions;
        String startTime;
        String stopTime;
        String weekDays;
        String actionsThen;
        String actionsElse;
        String actionsStart;
        String actionsStop;

        public RuleInfo(String name, String conditions, String startTime, String stopTime, String weekDays,
                String actionsThen, String actionsElse, String actionsStart, String actionsStop) {
            this.name = name;
            this.conditions = conditions;
            this.startTime = startTime;
            this.stopTime = stopTime;
            this.weekDays = weekDays;
            this.actionsThen = actionsThen;
            this.actionsElse = actionsElse;
            this.actionsStart = actionsStart;
            this.actionsStop = actionsStop;
        }

        public RuleInfo(GDProperties args) {
            name = args.getStringValue("name");
            conditions = args.getStringValue("conditions");
            startTime = args.getStringValue("startTime");
            stopTime = args.getStringValue("stopTime");
            weekDays = args.getStringValue("weekDays");
            actionsThen = args.getStringValue("actionsThen");
            actionsElse = args.getStringValue("actionsElse");
            actionsStart = args.getStringValue("actionsStart");
            actionsStop = args.getStringValue("actionsStop");
        }

    }
}