diff --git a/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/CurrentMonitorDao.java b/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/CurrentMonitorDao.java index 30ec3c0..7a51e5b 100644 --- a/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/CurrentMonitorDao.java +++ b/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/CurrentMonitorDao.java @@ -1,7 +1,7 @@ package com.lanternsoftware.dataaccess.currentmonitor; import com.lanternsoftware.datamodel.currentmonitor.Account; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig; import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup; import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy; diff --git a/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java b/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java index 3ca5724..7a70a38 100644 --- a/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java +++ b/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java @@ -1,7 +1,7 @@ package com.lanternsoftware.dataaccess.currentmonitor; import com.lanternsoftware.datamodel.currentmonitor.Account; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.currentmonitor.Breaker; import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig; import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup; @@ -14,9 +14,7 @@ import com.lanternsoftware.datamodel.currentmonitor.Sequence; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.DebugTimer; -import com.lanternsoftware.util.LanternFiles; import com.lanternsoftware.util.NullUtils; -import com.lanternsoftware.util.ResourceLoader; import com.lanternsoftware.util.cryptography.AESTool; import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoQuery; @@ -42,7 +40,7 @@ import java.util.concurrent.Executors; public class MongoCurrentMonitorDao implements CurrentMonitorDao { private static final Logger logger = LoggerFactory.getLogger(MongoCurrentMonitorDao.class); - private static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat")); + private static final AESTool aes = AESTool.authTool(); private static final int BCRYPT_ROUNDS = 11; private final Timer delayTimer = new Timer(); private final ExecutorService executor = Executors.newCachedThreadPool(); diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer b/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer index 55475d5..4bfec17 100644 --- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer +++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer @@ -1,5 +1,4 @@ com.lanternsoftware.datamodel.currentmonitor.dao.AccountSerializer -com.lanternsoftware.datamodel.currentmonitor.dao.AuthCodeSerializer com.lanternsoftware.datamodel.currentmonitor.dao.BreakerConfigSerializer com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupEnergySerializer com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupSerializer diff --git a/currentmonitor/lantern-service-currentmonitor/pom.xml b/currentmonitor/lantern-service-currentmonitor/pom.xml index adec441..0d36b0b 100644 --- a/currentmonitor/lantern-service-currentmonitor/pom.xml +++ b/currentmonitor/lantern-service-currentmonitor/pom.xml @@ -12,6 +12,18 @@ 1.8 + + + + com.google.api-client + google-api-client-bom + 1.32.1 + pom + import + + + + com.lanternsoftware.currentmonitor @@ -23,10 +35,14 @@ lantern-util-servlet 1.0.0 + + com.lanternsoftware.rules + lantern-service-rules + 1.0.0 + com.google.api-client google-api-client - 1.30.4 javax diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java index 3ee445c..890724d 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java @@ -2,6 +2,7 @@ package com.lanternsoftware.currentmonitor.context; import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao; import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao; +import com.lanternsoftware.rules.RulesEngine; import com.lanternsoftware.util.LanternFiles; import com.lanternsoftware.util.dao.mongo.MongoConfig; @@ -14,10 +15,12 @@ public class Globals implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg")); + RulesEngine.instance().start(); } @Override public void contextDestroyed(ServletContextEvent sce) { dao.shutdown(); + RulesEngine.shutdown(); } } diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/AuthServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/AuthServlet.java index 192127b..d770bbc 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/AuthServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/AuthServlet.java @@ -4,7 +4,7 @@ import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeToken import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse; import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.json.gson.GsonFactory; import com.lanternsoftware.currentmonitor.context.Globals; import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.LanternFiles; @@ -13,6 +13,7 @@ import com.lanternsoftware.util.ResourceLoader; import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoSerializer; import com.lanternsoftware.util.servlet.BasicAuth; +import com.lanternsoftware.util.servlet.LanternServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,9 +22,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/auth/*") -public class AuthServlet extends CMServlet { +public class AuthServlet extends LanternServlet { private static final NetHttpTransport transport = new NetHttpTransport(); - private static final JacksonFactory jsonFactory = new JacksonFactory(); private static final Logger logger = LoggerFactory.getLogger(AuthServlet.class); private static final String googleClientId; private static final String googleClientSecret; @@ -41,7 +41,7 @@ public class AuthServlet extends CMServlet { if (NullUtils.isEqual(auth.getUsername(), "googlesso")) { logger.info("Attempting google SSO"); try { - GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, jsonFactory, "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, auth.getPassword(), "").execute(); + GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, new GsonFactory(), "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, auth.getPassword(), "").execute(); if (tokenResponse != null) { GoogleIdToken idToken = tokenResponse.parseIdToken(); if (idToken != null) { diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/BomServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/BomServlet.java index e2d76f0..756136a 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/BomServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/BomServlet.java @@ -8,13 +8,14 @@ import com.lanternsoftware.util.csv.CSVWriter; import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoQuery; import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.servlet.LanternServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/bom/*") -public class BomServlet extends CMServlet { +public class BomServlet extends LanternServlet { @Override protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { String[] path = path(_req); diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CommandServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CommandServlet.java index 8003152..0672fc8 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CommandServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CommandServlet.java @@ -1,6 +1,6 @@ package com.lanternsoftware.currentmonitor.servlet; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.LanternFiles; import com.lanternsoftware.util.NullUtils; diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java index 86980a7..e48dd6f 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java @@ -1,11 +1,8 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.currentmonitor.context.Globals; -import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; @@ -13,13 +10,8 @@ import javax.servlet.http.HttpServletResponse; @WebServlet("/config/*") public class ConfigServlet extends SecureServlet { - private static final Logger logger = LoggerFactory.getLogger(ConfigServlet.class); - @Override protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { - if (_authCode.getAccountId() == 100) { - logger.error("my ip: " + _req.getRemoteAddr()); - } if (isPath(_req, 0, "bin")) zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode)); else diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GenerateBomServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GenerateBomServlet.java index 596949e..52c0893 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GenerateBomServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GenerateBomServlet.java @@ -1,7 +1,7 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.currentmonitor.context.Globals; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.dao.DaoEntity; import javax.servlet.annotation.WebServlet; diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupEnergyServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupEnergyServlet.java index 449729c..f42eafe 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupEnergyServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupEnergyServlet.java @@ -1,7 +1,7 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.currentmonitor.context.Globals; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy; import com.lanternsoftware.datamodel.currentmonitor.EnergyBlockViewMode; import com.lanternsoftware.util.CollectionUtils; diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupPowerServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupPowerServlet.java index 5af0898..29b4ed8 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupPowerServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/GroupPowerServlet.java @@ -1,15 +1,9 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.currentmonitor.context.Globals; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; -import com.lanternsoftware.datamodel.currentmonitor.Breaker; -import com.lanternsoftware.datamodel.currentmonitor.BreakerPower; -import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup; -import com.lanternsoftware.util.CollectionUtils; -import com.lanternsoftware.util.NullUtils; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoSerializer; -import org.bson.Document; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/PowerServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/PowerServlet.java index a0bd27c..3abca86 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/PowerServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/PowerServlet.java @@ -1,7 +1,7 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.currentmonitor.context.Globals; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.currentmonitor.BreakerPower; import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute; import com.lanternsoftware.util.CollectionUtils; @@ -31,7 +31,9 @@ public class PowerServlet extends SecureServlet { protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { String[] path = path(_req); if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "hub")) { - Globals.dao.putHubPowerMinute(getRequestPayload(_req, HubPowerMinute.class)); + HubPowerMinute m = getRequestPayload(_req, HubPowerMinute.class); + m.setAccountId(_authCode.getAccountId()); + Globals.dao.putHubPowerMinute(m); return; } if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "batch")) { diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SecureServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SecureServlet.java index bf89561..8dec803 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SecureServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SecureServlet.java @@ -1,12 +1,13 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.currentmonitor.context.Globals; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; +import com.lanternsoftware.util.servlet.LanternServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -public abstract class SecureServlet extends CMServlet { +public abstract class SecureServlet extends LanternServlet { @Override protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { AuthCode authCode = Globals.dao.decryptAuthCode(_req.getHeader("auth_code")); diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SignupServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SignupServlet.java index d6c956b..3a8a6a3 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SignupServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SignupServlet.java @@ -7,13 +7,14 @@ import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.email.EmailValidator; import com.lanternsoftware.util.servlet.BasicAuth; +import com.lanternsoftware.util.servlet.LanternServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/signup") -public class SignupServlet extends CMServlet { +public class SignupServlet extends LanternServlet { @Override protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { BasicAuth auth = new BasicAuth(_req); diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/UpdateServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/UpdateServlet.java index b5ab090..6383c7b 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/UpdateServlet.java +++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/UpdateServlet.java @@ -3,6 +3,7 @@ package com.lanternsoftware.currentmonitor.servlet; import com.lanternsoftware.util.LanternFiles; import com.lanternsoftware.util.ResourceLoader; import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.servlet.LanternServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; @@ -11,7 +12,7 @@ import javax.ws.rs.core.MediaType; import java.io.File; @WebServlet("/update/*") -public class UpdateServlet extends CMServlet { +public class UpdateServlet extends LanternServlet { @Override protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { if (isPath(_req, 0, "version")) diff --git a/pom.xml b/pom.xml index faaced3..93b94d2 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ currentmonitor util + rules zwave \ No newline at end of file diff --git a/rules/lantern-dataaccess-rules/pom.xml b/rules/lantern-dataaccess-rules/pom.xml new file mode 100644 index 0000000..725a824 --- /dev/null +++ b/rules/lantern-dataaccess-rules/pom.xml @@ -0,0 +1,78 @@ + + 4.0.0 + com.lanternsoftware.rules + lantern-dataaccess-rules + jar + 1.0.0 + lantern-dataaccess-rules + + + 1.8 + 1.8 + + + + + com.lanternsoftware.rules + lantern-datamodel-rules + 1.0.0 + + + com.lanternsoftware.util + lantern-util-dao-mongo + 1.0.0 + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + + + testCompile + + compile + + + + true + true + UTF-8 + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + package + + jar + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.5 + + + true + + + + + + diff --git a/rules/lantern-dataaccess-rules/src/main/java/com/lanternsoftware/dataaccess/rules/MongoRulesDataAccess.java b/rules/lantern-dataaccess-rules/src/main/java/com/lanternsoftware/dataaccess/rules/MongoRulesDataAccess.java new file mode 100644 index 0000000..f4a46cd --- /dev/null +++ b/rules/lantern-dataaccess-rules/src/main/java/com/lanternsoftware/dataaccess/rules/MongoRulesDataAccess.java @@ -0,0 +1,70 @@ +package com.lanternsoftware.dataaccess.rules; + +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.datamodel.rules.FcmDevice; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.util.dao.DaoQuery; +import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.dao.DaoSort; +import com.lanternsoftware.util.dao.mongo.MongoConfig; +import com.lanternsoftware.util.dao.mongo.MongoProxy; + +import java.util.Date; +import java.util.List; + +public class MongoRulesDataAccess implements RulesDataAccess { + private final MongoProxy proxy; + + public MongoRulesDataAccess(MongoConfig _config) { + proxy = new MongoProxy(_config); + proxy.ensureIndex(Rule.class, DaoSort.sort("account_id")); + proxy.ensureIndex(Event.class, DaoSort.sort("account_id").then("type").then("source_id").then("time")); + proxy.ensureIndex(FcmDevice.class, DaoSort.sort("account_id")); + } + + @Override + public void shutdown() { + proxy.shutdown(); + } + + @Override + public void putRule(Rule _rule) { + proxy.save(_rule); + } + + @Override + public List getRulesForAccount(int _accountId) { + return proxy.query(Rule.class, new DaoQuery("account_id", _accountId)); + } + + @Override + public void deleteRule(String _ruleId) { + proxy.delete(Rule.class, new DaoQuery("_id", _ruleId)); + } + + @Override + public void putEvent(Event _event) { + proxy.save(_event); + } + + @Override + public Event getMostRecentEvent(int _accountId, EventType _type, String _sourceId) { + return proxy.queryOne(Event.class, new DaoQuery("account_id", _accountId).and("type", DaoSerializer.toEnumName(_type)).and("source_id", _sourceId), DaoSort.sortDesc("time")); + } + + @Override + public List getEvents(int _accountId, EventType _type, String _sourceId, Date _from, Date _to) { + return proxy.query(Event.class, new DaoQuery("account_id", _accountId).and("type", DaoSerializer.toEnumName(_type)).and("source_id", _sourceId).andBetweenInclusiveExclusive("time", DaoSerializer.toLong(_from), DaoSerializer.toLong(_to))); + } + + @Override + public void putFcmDevice(FcmDevice _device) { + proxy.save(_device); + } + + @Override + public List getFcmDevicesForAccount(int _accountId) { + return proxy.query(FcmDevice.class, new DaoQuery("account_id", _accountId)); + } +} diff --git a/rules/lantern-dataaccess-rules/src/main/java/com/lanternsoftware/dataaccess/rules/RulesDataAccess.java b/rules/lantern-dataaccess-rules/src/main/java/com/lanternsoftware/dataaccess/rules/RulesDataAccess.java new file mode 100644 index 0000000..08535d4 --- /dev/null +++ b/rules/lantern-dataaccess-rules/src/main/java/com/lanternsoftware/dataaccess/rules/RulesDataAccess.java @@ -0,0 +1,21 @@ +package com.lanternsoftware.dataaccess.rules; + +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.datamodel.rules.FcmDevice; +import com.lanternsoftware.datamodel.rules.Rule; + +import java.util.Date; +import java.util.List; + +public interface RulesDataAccess { + void shutdown(); + void putRule(Rule _rule); + List getRulesForAccount(int _accountId); + void deleteRule(String _ruleId); + void putEvent(Event _event); + Event getMostRecentEvent(int _accountId, EventType _type, String _sourceId); + List getEvents(int _accountId, EventType _type, String _sourceId, Date _from, Date _to); + void putFcmDevice(FcmDevice _device); + List getFcmDevicesForAccount(int _accountId); +} diff --git a/rules/lantern-dataaccess-rules/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer b/rules/lantern-dataaccess-rules/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer new file mode 100644 index 0000000..e69de29 diff --git a/rules/lantern-datamodel-rules/pom.xml b/rules/lantern-datamodel-rules/pom.xml new file mode 100644 index 0000000..5c84ae6 --- /dev/null +++ b/rules/lantern-datamodel-rules/pom.xml @@ -0,0 +1,73 @@ + + 4.0.0 + com.lanternsoftware.rules + lantern-datamodel-rules + jar + 1.0.0 + lantern-datamodel-rules + + + 1.8 + 1.8 + + + + + com.lanternsoftware.util + lantern-util-dao + 1.0.0 + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + + + testCompile + + compile + + + + true + true + UTF-8 + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + package + + jar + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.5 + + + true + + + + + + diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Action.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Action.java new file mode 100644 index 0000000..176a245 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Action.java @@ -0,0 +1,43 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.dao.annotations.DBSerializable; + +@DBSerializable +public class Action { + private ActionType type; + private String description; + private String destinationId; + private double value; + + public ActionType getType() { + return type; + } + + public void setType(ActionType _type) { + type = _type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String _description) { + description = _description; + } + + public String getDestinationId() { + return destinationId; + } + + public void setDestinationId(String _destinationId) { + destinationId = _destinationId; + } + + public double getValue() { + return value; + } + + public void setValue(double _value) { + value = _value; + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/ActionType.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/ActionType.java new file mode 100644 index 0000000..188a9a6 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/ActionType.java @@ -0,0 +1,7 @@ +package com.lanternsoftware.datamodel.rules; + +public enum ActionType { + SET_SWITCH, + MOBILE_ALERT_STATIC, + MOBILE_ALERT_EVENT_DESCRIPTION +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Alert.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Alert.java new file mode 100644 index 0000000..676910e --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Alert.java @@ -0,0 +1,23 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.dao.annotations.DBSerializable; + +@DBSerializable +public class Alert { + private String message; + + public Alert() { + } + + public Alert(String _message) { + message = _message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String _message) { + message = _message; + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Criteria.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Criteria.java new file mode 100644 index 0000000..b660d20 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Criteria.java @@ -0,0 +1,172 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.CollectionUtils; +import com.lanternsoftware.util.DateUtils; +import com.lanternsoftware.util.NullUtils; +import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.dao.annotations.DBSerializable; + +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; + +@DBSerializable +public class Criteria { + private EventType type; + private String sourceId; + private Operator operator; + private double value; + private boolean or; + private List criteria; + + public EventType getType() { + return type; + } + + public void setType(EventType _type) { + type = _type; + } + + public String getSourceId() { + return sourceId; + } + + public void setSourceId(String _sourceId) { + sourceId = _sourceId; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator _operator) { + operator = _operator; + } + + public double getValue() { + return value; + } + + public void setValue(double _value) { + value = _value; + } + + public boolean isOr() { + return or; + } + + public void setOr(boolean _or) { + or = _or; + } + + public List getCriteria() { + return criteria; + } + + public void setCriteria(List _criteria) { + criteria = _criteria; + } + + public EventId toEventId() { + return new EventId(type, sourceId); + } + + public Set toJavaDays() { + if (type != EventType.TIME) + return Collections.emptySet(); + return CollectionUtils.transformToSet(CriteriaDay.toEnumSet(sourceId), _d->_d.javaDay); + } + + public boolean isMet(List _events, TimeZone _tz) { + Event e = CollectionUtils.filterOne(_events, this::triggers); + if (type == EventType.TIME) { + int day = DateUtils.toCalendar(new Date(), _tz).get(Calendar.DAY_OF_WEEK); + if (!toJavaDays().contains(day)) + return false; + Date timeToday = timeOfDay(new Date(), DaoSerializer.toInteger(getValue()), day, _tz); + if (!e.getTime().equals(timeToday)) + return false; + } + else if (operator != null) { + if (operator == Operator.GREATER) { + if (e.getValue() <= value) + return false; + } + else if (operator == Operator.GREATER_EQUAL) { + if (e.getValue() < value) + return false; + } + else if (operator == Operator.EQUAL) { + if (e.getValue() != value) + return false; + } + else if (operator == Operator.LESS_EQUAL) { + if (e.getValue() > value) + return false; + } + else if (operator == Operator.LESS) { + if (e.getValue() >= value) + return false; + } + } + if (CollectionUtils.isNotEmpty(criteria)) { + if (or) + return CollectionUtils.anyQualify(criteria, _c->_c.isMet(_events, _tz)); + return CollectionUtils.allQualify(criteria, _c->_c.isMet(_events, _tz)); + } + return true; + } + + public boolean triggers(Event _event) { + if (_event.getType() != type) + return false; + if (NullUtils.isEmpty(_event.getSourceId()) || NullUtils.isEqual(_event.getSourceId(), "*") || NullUtils.isEqual(_event.getSourceId(), sourceId)) + return true; + return CollectionUtils.anyQualify(criteria, _c->_c.triggers(_event)); + } + + public void addAllCriteria(List _criteria) { + _criteria.add(this); + CollectionUtils.edit(criteria, _c->_c.addAllCriteria(_criteria)); + } + + public Date getNextTriggerDate(TimeZone _tz) { + if (type != EventType.TIME) + return null; + Collection dates = CollectionUtils.transform(CriteriaDay.toEnumSet(getSourceId()), _s->nextTimeOfDay(new Date(), DaoSerializer.toInteger(getValue()), _s.javaDay, _tz)); + return CollectionUtils.getSmallest(dates); + } + + public Date timeOfDay(Date _now, int _time, int _day, TimeZone _tz) { + Calendar cal = DateUtils.toCalendar(_now, _tz); + cal.set(Calendar.DAY_OF_WEEK, _day); + cal.set(Calendar.HOUR_OF_DAY, hour(_time)); + cal.set(Calendar.MINUTE, minute(_time)); + cal.set(Calendar.SECOND, second(_time)); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + public Date nextTimeOfDay(Date _now, int _time, int _day, TimeZone _tz) { + Date time = timeOfDay(_now, _time, _day, _tz); + return time.before(_now)?DateUtils.addDays(time,7, _tz):time; + } + + public int hour(int _timeOfDay) { + return _timeOfDay/3600; + } + + public int minute(int _timeOfDay) { + return (_timeOfDay/60)%60; + } + + public int second(int _timeOfDay) { + return _timeOfDay%60; + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/CriteriaDay.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/CriteriaDay.java new file mode 100644 index 0000000..f171717 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/CriteriaDay.java @@ -0,0 +1,35 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.CollectionUtils; +import com.lanternsoftware.util.NullUtils; + +import java.util.Calendar; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Set; + +public enum CriteriaDay { + SUN(Calendar.SUNDAY), + MON(Calendar.MONDAY), + TUE(Calendar.TUESDAY), + WED(Calendar.WEDNESDAY), + THU(Calendar.THURSDAY), + FRI(Calendar.FRIDAY), + SAT(Calendar.SATURDAY); + + public final int javaDay; + + CriteriaDay(int _javaDay) { + javaDay = _javaDay; + } + + public static String toString(Collection _coll) { + return CollectionUtils.transformToCommaSeparated(_coll, Enum::name, false); + } + + public static EnumSet toEnumSet(String _days) { + String[] days = NullUtils.cleanSplit(_days, ","); + Set setDays = CollectionUtils.transformToSet(CollectionUtils.asArrayList(days), _s->NullUtils.toEnum(CriteriaDay.class, _s)); + return setDays.isEmpty()?EnumSet.allOf(CriteriaDay.class):EnumSet.copyOf(setDays); + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Event.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Event.java new file mode 100644 index 0000000..7ae3aa6 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Event.java @@ -0,0 +1,73 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.dao.annotations.DBSerializable; +import com.lanternsoftware.util.dao.annotations.PrimaryKey; + +import java.util.Date; + +@DBSerializable +public class Event { + @PrimaryKey private String id; + private int accountId; + private EventType type; + private Date time; + private String eventDescription; + private String sourceId; + private double value; + + public String getId() { + return id; + } + + public void setId(String _id) { + id = _id; + } + + public int getAccountId() { + return accountId; + } + + public void setAccountId(int _accountId) { + accountId = _accountId; + } + + public EventType getType() { + return type; + } + + public void setType(EventType _type) { + type = _type; + } + + public Date getTime() { + return time; + } + + public void setTime(Date _time) { + time = _time; + } + + public String getEventDescription() { + return eventDescription; + } + + public void setEventDescription(String _eventDescription) { + eventDescription = _eventDescription; + } + + public String getSourceId() { + return sourceId; + } + + public void setSourceId(String _sourceId) { + sourceId = _sourceId; + } + + public double getValue() { + return value; + } + + public void setValue(double _value) { + value = _value; + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/EventId.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/EventId.java new file mode 100644 index 0000000..e906d67 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/EventId.java @@ -0,0 +1,34 @@ +package com.lanternsoftware.datamodel.rules; + +import java.util.Objects; + +public class EventId { + private final EventType type; + private final String sourceId; + + public EventId(EventType _type, String _sourceId) { + type = _type; + sourceId = _sourceId; + } + + public EventType getType() { + return type; + } + + public String getSourceId() { + return sourceId; + } + + @Override + public boolean equals(Object _o) { + if (this == _o) return true; + if (_o == null || getClass() != _o.getClass()) return false; + EventId eventId = (EventId) _o; + return type == eventId.type && Objects.equals(sourceId, eventId.sourceId); + } + + @Override + public int hashCode() { + return Objects.hash(type, sourceId); + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/EventType.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/EventType.java new file mode 100644 index 0000000..cedf880 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/EventType.java @@ -0,0 +1,8 @@ +package com.lanternsoftware.datamodel.rules; + +public enum EventType { + SWITCH_LEVEL, + TEMPERATURE, + TIME, + POWER +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/FcmDevice.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/FcmDevice.java new file mode 100644 index 0000000..34f654e --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/FcmDevice.java @@ -0,0 +1,65 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.dao.annotations.DBSerializable; +import com.lanternsoftware.util.dao.annotations.PrimaryKey; + +import java.util.Date; + +@DBSerializable +public class FcmDevice { + @PrimaryKey private String id; + private int accountId; + private String token; + private String name; + private Date posted; + + public FcmDevice() { + } + + public FcmDevice(int _accountId, String _token, String _name, Date _posted) { + accountId = _accountId; + token = _token; + name = _name; + posted = _posted; + } + + public String getId() { + return id; + } + + public void setId(String _id) { + id = _id; + } + + public int getAccountId() { + return accountId; + } + + public void setAccountId(int _accountId) { + accountId = _accountId; + } + + public String getToken() { + return token; + } + + public void setToken(String _token) { + token = _token; + } + + public String getName() { + return name; + } + + public void setName(String _name) { + name = _name; + } + + public Date getPosted() { + return posted; + } + + public void setPosted(Date _posted) { + posted = _posted; + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Operator.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Operator.java new file mode 100644 index 0000000..1291c9f --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Operator.java @@ -0,0 +1,9 @@ +package com.lanternsoftware.datamodel.rules; + +public enum Operator { + GREATER, + GREATER_EQUAL, + EQUAL, + LESS_EQUAL, + LESS +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Rule.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Rule.java new file mode 100644 index 0000000..386e035 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/Rule.java @@ -0,0 +1,80 @@ +package com.lanternsoftware.datamodel.rules; + +import com.lanternsoftware.util.CollectionUtils; +import com.lanternsoftware.util.dao.annotations.DBSerializable; +import com.lanternsoftware.util.dao.annotations.PrimaryKey; + +import java.util.ArrayList; +import java.util.List; +import java.util.TimeZone; + +@DBSerializable +public class Rule { + @PrimaryKey private String id; + private int accountId; + private boolean or; + private List criteria; + private List actions; + + public String getId() { + return id; + } + + public void setId(String _id) { + id = _id; + } + + public int getAccountId() { + return accountId; + } + + public void setAccountId(int _accountId) { + accountId = _accountId; + } + + public boolean isOr() { + return or; + } + + public void setOr(boolean _or) { + or = _or; + } + + public List getCriteria() { + return criteria; + } + + public List getAllCriteria() { + List allCriteria = new ArrayList<>(); + CollectionUtils.edit(criteria, _c->_c.addAllCriteria(allCriteria)); + return allCriteria; + } + + public void setCriteria(List _criteria) { + criteria = _criteria; + } + + public List getActions() { + return actions; + } + + public void setActions(List _actions) { + actions = _actions; + } + + public boolean isMet(List _events, TimeZone _tz) { + if (or) + return CollectionUtils.anyQualify(criteria, _c->_c.isMet(_events, _tz)); + return CollectionUtils.allQualify(criteria, _c->_c.isMet(_events, _tz)); + } + + public List getCriteriaNeedingData(Event _event) { + List allCriteria = getAllCriteria(); + allCriteria.removeIf(_c->_c.triggers(_event)); + return allCriteria; + } + + public boolean triggers(Event _event) { + return CollectionUtils.anyQualify(criteria, _c-> _c.triggers(_event)); + } +} diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/ActionSerializer.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/ActionSerializer.java new file mode 100644 index 0000000..e3af7ed --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/ActionSerializer.java @@ -0,0 +1,46 @@ +package com.lanternsoftware.datamodel.rules.dao; + +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.ActionType; +import com.lanternsoftware.util.dao.AbstractDaoSerializer; +import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; +import com.lanternsoftware.util.dao.DaoSerializer; +import java.util.Collections; +import java.util.List; + +public class ActionSerializer extends AbstractDaoSerializer +{ + @Override + public Class getSupportedClass() + { + return Action.class; + } + + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + + @Override + public DaoEntity toDaoEntity(Action _o) + { + DaoEntity d = new DaoEntity(); + d.put("type", DaoSerializer.toEnumName(_o.getType())); + d.put("description", _o.getDescription()); + d.put("destination_id", _o.getDestinationId()); + d.put("value", _o.getValue()); + return d; + } + + @Override + public Action fromDaoEntity(DaoEntity _d) + { + Action o = new Action(); + o.setType(DaoSerializer.getEnum(_d, "type", ActionType.class)); + o.setDescription(DaoSerializer.getString(_d, "description")); + o.setDestinationId(DaoSerializer.getString(_d, "destination_id")); + o.setValue(DaoSerializer.getDouble(_d, "value")); + return o; + } +} \ No newline at end of file diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/AlertSerializer.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/AlertSerializer.java new file mode 100644 index 0000000..bc4fe64 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/AlertSerializer.java @@ -0,0 +1,39 @@ +package com.lanternsoftware.datamodel.rules.dao; + +import com.lanternsoftware.datamodel.rules.Alert; +import com.lanternsoftware.util.dao.AbstractDaoSerializer; +import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; +import com.lanternsoftware.util.dao.DaoSerializer; +import java.util.Collections; +import java.util.List; + +public class AlertSerializer extends AbstractDaoSerializer +{ + @Override + public Class getSupportedClass() + { + return Alert.class; + } + + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + + @Override + public DaoEntity toDaoEntity(Alert _o) + { + DaoEntity d = new DaoEntity(); + d.put("message", _o.getMessage()); + return d; + } + + @Override + public Alert fromDaoEntity(DaoEntity _d) + { + Alert o = new Alert(); + o.setMessage(DaoSerializer.getString(_d, "message")); + return o; + } +} \ No newline at end of file diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/CriteriaSerializer.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/CriteriaSerializer.java new file mode 100644 index 0000000..2cd2068 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/CriteriaSerializer.java @@ -0,0 +1,51 @@ +package com.lanternsoftware.datamodel.rules.dao; + +import com.lanternsoftware.datamodel.rules.Criteria; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.datamodel.rules.Operator; +import com.lanternsoftware.util.dao.AbstractDaoSerializer; +import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; +import com.lanternsoftware.util.dao.DaoSerializer; +import java.util.Collections; +import java.util.List; + +public class CriteriaSerializer extends AbstractDaoSerializer +{ + @Override + public Class getSupportedClass() + { + return Criteria.class; + } + + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + + @Override + public DaoEntity toDaoEntity(Criteria _o) + { + DaoEntity d = new DaoEntity(); + d.put("type", DaoSerializer.toEnumName(_o.getType())); + d.put("source_id", _o.getSourceId()); + d.put("operator", DaoSerializer.toEnumName(_o.getOperator())); + d.put("value", _o.getValue()); + d.put("or", _o.isOr()); + d.put("criteria", DaoSerializer.toDaoEntities(_o.getCriteria(), DaoProxyType.MONGO)); + return d; + } + + @Override + public Criteria fromDaoEntity(DaoEntity _d) + { + Criteria o = new Criteria(); + o.setType(DaoSerializer.getEnum(_d, "type", EventType.class)); + o.setSourceId(DaoSerializer.getString(_d, "source_id")); + o.setOperator(DaoSerializer.getEnum(_d, "operator", Operator.class)); + o.setValue(DaoSerializer.getDouble(_d, "value")); + o.setOr(DaoSerializer.getBoolean(_d, "or")); + o.setCriteria(DaoSerializer.getList(_d, "criteria", Criteria.class)); + return o; + } +} \ No newline at end of file diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/EventSerializer.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/EventSerializer.java new file mode 100644 index 0000000..a45b893 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/EventSerializer.java @@ -0,0 +1,53 @@ +package com.lanternsoftware.datamodel.rules.dao; + +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.util.dao.AbstractDaoSerializer; +import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; +import com.lanternsoftware.util.dao.DaoSerializer; +import java.util.Collections; +import java.util.List; + +public class EventSerializer extends AbstractDaoSerializer +{ + @Override + public Class getSupportedClass() + { + return Event.class; + } + + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + + @Override + public DaoEntity toDaoEntity(Event _o) + { + DaoEntity d = new DaoEntity(); + if (_o.getId() != null) + d.put("_id", _o.getId()); + d.put("account_id", _o.getAccountId()); + d.put("type", DaoSerializer.toEnumName(_o.getType())); + d.put("time", DaoSerializer.toLong(_o.getTime())); + d.put("event_description", _o.getEventDescription()); + d.put("source_id", _o.getSourceId()); + d.put("value", _o.getValue()); + return d; + } + + @Override + public Event fromDaoEntity(DaoEntity _d) + { + Event o = new Event(); + o.setId(DaoSerializer.getString(_d, "_id")); + o.setAccountId(DaoSerializer.getInteger(_d, "account_id")); + o.setType(DaoSerializer.getEnum(_d, "type", EventType.class)); + o.setTime(DaoSerializer.getDate(_d, "time")); + o.setEventDescription(DaoSerializer.getString(_d, "event_description")); + o.setSourceId(DaoSerializer.getString(_d, "source_id")); + o.setValue(DaoSerializer.getDouble(_d, "value")); + return o; + } +} \ No newline at end of file diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/FcmDeviceSerializer.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/FcmDeviceSerializer.java new file mode 100644 index 0000000..8d23c44 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/FcmDeviceSerializer.java @@ -0,0 +1,48 @@ +package com.lanternsoftware.datamodel.rules.dao; + +import com.lanternsoftware.datamodel.rules.FcmDevice; +import com.lanternsoftware.util.dao.AbstractDaoSerializer; +import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; +import com.lanternsoftware.util.dao.DaoSerializer; +import java.util.Collections; +import java.util.List; + +public class FcmDeviceSerializer extends AbstractDaoSerializer +{ + @Override + public Class getSupportedClass() + { + return FcmDevice.class; + } + + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + + @Override + public DaoEntity toDaoEntity(FcmDevice _o) + { + DaoEntity d = new DaoEntity(); + if (_o.getId() != null) + d.put("_id", _o.getId()); + d.put("account_id", _o.getAccountId()); + d.put("token", _o.getToken()); + d.put("name", _o.getName()); + d.put("posted", DaoSerializer.toLong(_o.getPosted())); + return d; + } + + @Override + public FcmDevice fromDaoEntity(DaoEntity _d) + { + FcmDevice o = new FcmDevice(); + o.setId(DaoSerializer.getString(_d, "_id")); + o.setAccountId(DaoSerializer.getInteger(_d, "account_id")); + o.setToken(DaoSerializer.getString(_d, "token")); + o.setName(DaoSerializer.getString(_d, "name")); + o.setPosted(DaoSerializer.getDate(_d, "posted")); + return o; + } +} \ No newline at end of file diff --git a/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/RuleSerializer.java b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/RuleSerializer.java new file mode 100644 index 0000000..2095ab2 --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/java/com/lanternsoftware/datamodel/rules/dao/RuleSerializer.java @@ -0,0 +1,50 @@ +package com.lanternsoftware.datamodel.rules.dao; + +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.Criteria; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.util.dao.AbstractDaoSerializer; +import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; +import com.lanternsoftware.util.dao.DaoSerializer; +import java.util.Collections; +import java.util.List; + +public class RuleSerializer extends AbstractDaoSerializer +{ + @Override + public Class getSupportedClass() + { + return Rule.class; + } + + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + + @Override + public DaoEntity toDaoEntity(Rule _o) + { + DaoEntity d = new DaoEntity(); + if (_o.getId() != null) + d.put("_id", _o.getId()); + d.put("account_id", _o.getAccountId()); + d.put("or", _o.isOr()); + d.put("criteria", DaoSerializer.toDaoEntities(_o.getCriteria(), DaoProxyType.MONGO)); + d.put("actions", DaoSerializer.toDaoEntities(_o.getActions(), DaoProxyType.MONGO)); + return d; + } + + @Override + public Rule fromDaoEntity(DaoEntity _d) + { + Rule o = new Rule(); + o.setId(DaoSerializer.getString(_d, "_id")); + o.setAccountId(DaoSerializer.getInteger(_d, "account_id")); + o.setOr(DaoSerializer.getBoolean(_d, "or")); + o.setCriteria(DaoSerializer.getList(_d, "criteria", Criteria.class)); + o.setActions(DaoSerializer.getList(_d, "actions", Action.class)); + return o; + } +} \ No newline at end of file diff --git a/rules/lantern-datamodel-rules/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer b/rules/lantern-datamodel-rules/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer new file mode 100644 index 0000000..96f0cdc --- /dev/null +++ b/rules/lantern-datamodel-rules/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer @@ -0,0 +1,6 @@ +com.lanternsoftware.datamodel.rules.dao.ActionSerializer +com.lanternsoftware.datamodel.rules.dao.AlertSerializer +com.lanternsoftware.datamodel.rules.dao.CriteriaSerializer +com.lanternsoftware.datamodel.rules.dao.EventSerializer +com.lanternsoftware.datamodel.rules.dao.FcmDeviceSerializer +com.lanternsoftware.datamodel.rules.dao.RuleSerializer diff --git a/rules/lantern-service-rules/pom.xml b/rules/lantern-service-rules/pom.xml new file mode 100644 index 0000000..1196897 --- /dev/null +++ b/rules/lantern-service-rules/pom.xml @@ -0,0 +1,93 @@ + + 4.0.0 + com.lanternsoftware.rules + lantern-service-rules + jar + 1.0.0 + lantern-service-rules + + + 1.8 + 1.8 + + + + + + com.google.api-client + google-api-client-bom + 1.32.1 + pom + import + + + + + + + com.google.api-client + google-api-client + + + com.google.firebase + firebase-admin + 8.0.0 + + + com.lanternsoftware.rules + lantern-dataaccess-rules + 1.0.0 + + + com.lanternsoftware.currentmonitor + lantern-dataaccess-currentmonitor + 1.0.0 + + + com.lanternsoftware.util + lantern-util-servlet + 1.0.0 + + + javax + javaee-api + 8.0 + provided + + + org.slf4j + slf4j-api + 1.7.29 + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + + + testCompile + + compile + + + + true + true + UTF-8 + 1.8 + 1.8 + + + + + diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java new file mode 100644 index 0000000..b06a2b8 --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java @@ -0,0 +1,147 @@ +package com.lanternsoftware.rules; + +import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao; +import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao; +import com.lanternsoftware.dataaccess.rules.MongoRulesDataAccess; +import com.lanternsoftware.dataaccess.rules.RulesDataAccess; +import com.lanternsoftware.datamodel.currentmonitor.Account; +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.ActionType; +import com.lanternsoftware.datamodel.rules.Criteria; +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.EventId; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.rules.actions.ActionImpl; +import com.lanternsoftware.util.CollectionUtils; +import com.lanternsoftware.util.DateUtils; +import com.lanternsoftware.util.LanternFiles; +import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.dao.mongo.MongoConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.TimeZone; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class RulesEngine { + protected static final Logger LOG = LoggerFactory.getLogger(RulesEngine.class); + + private static RulesEngine INSTANCE; + private final ExecutorService executor = Executors.newCachedThreadPool(); + private final RulesDataAccess dao; + private final CurrentMonitorDao cmDao; + private final Map actions = new HashMap<>(); + private final Map timeTasks = new HashMap<>(); + private Timer timer; + + + public static RulesEngine instance() { + if (INSTANCE == null) + INSTANCE = new RulesEngine(); + return INSTANCE; + } + + public RulesEngine() { + ServiceLoader.load(ActionImpl.class).forEach(_action->actions.put(_action.getType(), _action)); + dao = new MongoRulesDataAccess(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg")); + cmDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg")); + timer = new Timer("RulesEngine Timer"); + } + + public void start() { + for (String id : cmDao.getProxy().queryForField(Account.class, null, "_id")) { + scheduleNextTimeEventForAccount(DaoSerializer.toInteger(id)); + } + } + + public RulesDataAccess dao() { + return dao; + } + + public void fireEvent(Event _event) { + if (_event.getType() != EventType.TIME) + dao.putEvent(_event); + executor.submit(()->{ + TimeZone tz = TimeZone.getTimeZone("America/Chicago"); //TODO: Get from the current monitor account + List rules = CollectionUtils.filter(dao.getRulesForAccount(_event.getAccountId()), _r->_r.triggers(_event)); + if (!rules.isEmpty()) { + for (Rule rule : rules) { + List events = CollectionUtils.asArrayList(_event); + List critNeedingData = rule.getCriteriaNeedingData(_event); + if (!critNeedingData.isEmpty()) { + Set eventsToGet = CollectionUtils.transformToSet(critNeedingData, Criteria::toEventId); + for (EventId id : eventsToGet) { + Event event = dao.getMostRecentEvent(_event.getAccountId(), id.getType(), id.getSourceId()); + if (event != null) + events.add(event); + } + } + if (rule.isMet(events, tz)) { + for (Action action : CollectionUtils.makeNotNull(rule.getActions())) { + ActionImpl impl = actions.get(action.getType()); + impl.invoke(rule, events, action); + } + } + } + } + }); + } + + private void scheduleNextTimeEventForAccount(int _accountId) { + TimeZone tz = TimeZone.getTimeZone("America/Chicago"); //TODO: Get from the current monitor account + EventTimeTask nextTask = timeTasks.remove(_accountId); + if (nextTask != null) + nextTask.cancel(); + List rules = CollectionUtils.filter(dao.getRulesForAccount(_accountId), _r->CollectionUtils.anyQualify(_r.getAllCriteria(), _c->_c.getType() == EventType.TIME)); + if (rules.isEmpty()) + return; + Collection dates = CollectionUtils.aggregate(rules, _r->CollectionUtils.transform(_r.getAllCriteria(), _c->_c.getNextTriggerDate(tz))); + Date nextDate = CollectionUtils.getSmallest(dates); + LOG.info("Scheduling next time event for account {} at {}", _accountId, DateUtils.format("MM/dd/yyyy HH:mm:ss", nextDate)); + nextTask = new EventTimeTask(_accountId, nextDate); + timer.schedule(nextTask, nextDate); + } + + public static void shutdown() { + if (INSTANCE == null) + return; + INSTANCE.executor.shutdown(); + INSTANCE.dao.shutdown(); + INSTANCE.cmDao.shutdown(); + INSTANCE.timer.cancel(); + INSTANCE.timer = null; + INSTANCE = null; + } + + private class EventTimeTask extends TimerTask { + private final int accountId; + private final Date eventTime; + + EventTimeTask(int _accountId, Date _eventTime) { + accountId = _accountId; + eventTime = _eventTime; + } + + @Override + public void run() { + LOG.info("Firing time event for account {}", accountId); + Event event = new Event(); + event.setAccountId(accountId); + event.setTime(eventTime); + event.setType(EventType.TIME); + fireEvent(event); + scheduleNextTimeEventForAccount(accountId); + } + } +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java new file mode 100644 index 0000000..ab531b5 --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java @@ -0,0 +1,52 @@ +package com.lanternsoftware.rules.actions; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.AndroidConfig; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Message; +import com.lanternsoftware.datamodel.rules.Alert; +import com.lanternsoftware.datamodel.rules.FcmDevice; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.rules.RulesEngine; +import com.lanternsoftware.util.LanternFiles; +import com.lanternsoftware.util.dao.DaoSerializer; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.util.List; + +public abstract class AbstractAlertAction implements ActionImpl { + protected static final Logger logger = LoggerFactory.getLogger(AbstractAlertAction.class); + protected static final FirebaseMessaging messaging; + static { + FirebaseMessaging m = null; + try { + FileInputStream is = new FileInputStream(LanternFiles.OPS_PATH + "google_account_key.json"); + FirebaseOptions options = FirebaseOptions.builder().setCredentials(GoogleCredentials.fromStream(is)).build(); + m = FirebaseMessaging.getInstance(FirebaseApp.initializeApp(options)); + IOUtils.closeQuietly(is); + } + catch (Exception _e) { + logger.error("Failed to load google credentials", _e); + } + messaging = m; + } + + protected void sendAlert(Rule _rule, Alert _alert) { + List devices = RulesEngine.instance().dao().getFcmDevicesForAccount(_rule.getAccountId()); + if (devices.isEmpty()) + return; + for (FcmDevice device : devices) { + Message msg = Message.builder().setToken(device.getToken()).putData("payload", DaoSerializer.toBase64ZipBson(_alert)).putData("payloadClass", Alert.class.getCanonicalName()).setAndroidConfig(AndroidConfig.builder().setPriority(AndroidConfig.Priority.HIGH).setDirectBootOk(true).build()).build(); + try { + messaging.send(msg); + } catch (Exception _e) { + logger.error("Failed to send message to account {}, device {}", _rule.getAccountId(), device.getName(), _e); + } + } + } +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/ActionImpl.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/ActionImpl.java new file mode 100644 index 0000000..bf9ca70 --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/ActionImpl.java @@ -0,0 +1,13 @@ +package com.lanternsoftware.rules.actions; + +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.ActionType; +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.Rule; + +import java.util.List; + +public interface ActionImpl { + ActionType getType(); + void invoke(Rule _rule, List _event, Action _action); +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/MobileAlertAction.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/MobileAlertAction.java new file mode 100644 index 0000000..f73bfb4 --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/MobileAlertAction.java @@ -0,0 +1,22 @@ +package com.lanternsoftware.rules.actions; + +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.ActionType; +import com.lanternsoftware.datamodel.rules.Alert; +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.util.CollectionUtils; + +import java.util.List; + +public class MobileAlertAction extends AbstractAlertAction { + @Override + public ActionType getType() { + return ActionType.MOBILE_ALERT_EVENT_DESCRIPTION; + } + + @Override + public void invoke(Rule _rule, List _event, Action _action) { + sendAlert(_rule, new Alert(CollectionUtils.transformToCommaSeparated(_event, Event::getEventDescription))); + } +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/MobileAlertStatic.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/MobileAlertStatic.java new file mode 100644 index 0000000..a301ae7 --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/MobileAlertStatic.java @@ -0,0 +1,22 @@ +package com.lanternsoftware.rules.actions; + +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.ActionType; +import com.lanternsoftware.datamodel.rules.Alert; +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.util.CollectionUtils; + +import java.util.List; + +public class MobileAlertStatic extends AbstractAlertAction { + @Override + public ActionType getType() { + return ActionType.MOBILE_ALERT_STATIC; + } + + @Override + public void invoke(Rule _rule, List _event, Action _action) { + sendAlert(_rule, new Alert(_action.getDescription())); + } +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/EventServlet.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/EventServlet.java new file mode 100644 index 0000000..235c43f --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/EventServlet.java @@ -0,0 +1,24 @@ +package com.lanternsoftware.rules.servlet; + + +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.rules.RulesEngine; +import com.lanternsoftware.util.dao.auth.AuthCode; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/event") +public class EventServlet extends SecureServlet { + @Override + protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { + Event event = getRequestPayload(_req, Event.class); + if (event == null) { + _rep.setStatus(400); + return; + } + event.setAccountId(_authCode.getAccountId()); + RulesEngine.instance().fireEvent(event); + } +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/FcmServlet.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/FcmServlet.java new file mode 100644 index 0000000..1e03a5a --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/FcmServlet.java @@ -0,0 +1,24 @@ +package com.lanternsoftware.rules.servlet; + + +import com.lanternsoftware.datamodel.rules.FcmDevice; +import com.lanternsoftware.rules.RulesEngine; +import com.lanternsoftware.util.dao.auth.AuthCode; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/fcm") +public class FcmServlet extends SecureServlet { + @Override + protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { + FcmDevice device = getRequestPayload(_req, FcmDevice.class); + if (device == null) { + _rep.setStatus(400); + return; + } + device.setAccountId(_authCode.getAccountId()); + RulesEngine.instance().dao().putFcmDevice(device); + } +} diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/SecureServlet.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/SecureServlet.java new file mode 100644 index 0000000..cadc3dc --- /dev/null +++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/servlet/SecureServlet.java @@ -0,0 +1,39 @@ +package com.lanternsoftware.rules.servlet; + +import com.lanternsoftware.util.cryptography.AESTool; +import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.dao.auth.AuthCode; +import com.lanternsoftware.util.servlet.LanternServlet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public abstract class SecureServlet extends LanternServlet { + private static final AESTool aes = AESTool.authTool(); + + @Override + protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { + AuthCode authCode = DaoSerializer.fromZipBson(aes.decryptFromBase64(_req.getHeader("auth_code")), AuthCode.class); + if (authCode == null) { + _rep.setStatus(401); + return; + } + get(authCode, _req, _rep); + } + + protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { + } + + @Override + protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) { + AuthCode authCode = DaoSerializer.fromZipBson(aes.decryptFromBase64(_req.getHeader("auth_code")), AuthCode.class); + if (authCode == null) { + _rep.setStatus(401); + return; + } + post(authCode, _req, _rep); + } + + protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { + } +} diff --git a/rules/lantern-service-rules/src/main/resources/META-INF/services/com.lanternsoftware.rules.actions.ActionImpl b/rules/lantern-service-rules/src/main/resources/META-INF/services/com.lanternsoftware.rules.actions.ActionImpl new file mode 100644 index 0000000..3cc4cd4 --- /dev/null +++ b/rules/lantern-service-rules/src/main/resources/META-INF/services/com.lanternsoftware.rules.actions.ActionImpl @@ -0,0 +1,2 @@ +com.lanternsoftware.rules.actions.MobileAlertAction +com.lanternsoftware.rules.actions.MobileAlertStatic diff --git a/rules/lantern-service-rules/src/test/java/com/lanternsoftware/CreateRules.java b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/CreateRules.java new file mode 100644 index 0000000..5cfbf25 --- /dev/null +++ b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/CreateRules.java @@ -0,0 +1,165 @@ +package com.lanternsoftware; + +import com.lanternsoftware.datamodel.rules.Action; +import com.lanternsoftware.datamodel.rules.ActionType; +import com.lanternsoftware.datamodel.rules.Criteria; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.datamodel.rules.Operator; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.rules.RulesEngine; +import com.lanternsoftware.util.CollectionUtils; + +public class CreateRules { + public static void main(String[] args) { + for (Rule r : RulesEngine.instance().dao().getRulesForAccount(100)) { + RulesEngine.instance().dao().deleteRule(r.getId()); + } + Rule r1 = new Rule(); + r1.setAccountId(100); + Criteria c1 = new Criteria(); + c1.setType(EventType.SWITCH_LEVEL); + c1.setSourceId("203"); + c1.setOperator(Operator.EQUAL); + c1.setValue(1); + r1.setCriteria(CollectionUtils.asArrayList(c1)); + Action a1 = new Action(); + a1.setType(ActionType.MOBILE_ALERT_STATIC); + a1.setDescription("Garage Door 1 opened"); + a1.setDestinationId("*"); + r1.setActions(CollectionUtils.asArrayList(a1)); + RulesEngine.instance().dao().putRule(r1); + + Rule r2 = new Rule(); + r2.setAccountId(100); + Criteria c2 = new Criteria(); + c2.setType(EventType.SWITCH_LEVEL); + c2.setSourceId("203"); + c2.setOperator(Operator.EQUAL); + c2.setValue(0); + r2.setCriteria(CollectionUtils.asArrayList(c2)); + Action a2 = new Action(); + a2.setType(ActionType.MOBILE_ALERT_STATIC); + a2.setDescription("Garage Door 1 closed"); + a2.setDestinationId("*"); + r2.setActions(CollectionUtils.asArrayList(a2)); + RulesEngine.instance().dao().putRule(r2); + + Rule r3 = new Rule(); + r3.setAccountId(100); + Criteria c3 = new Criteria(); + c3.setType(EventType.SWITCH_LEVEL); + c3.setSourceId("204"); + c3.setOperator(Operator.EQUAL); + c3.setValue(1); + r3.setCriteria(CollectionUtils.asArrayList(c3)); + Action a3 = new Action(); + a3.setType(ActionType.MOBILE_ALERT_STATIC); + a3.setDescription("Garage Door 2 opened"); + a3.setDestinationId("*"); + r3.setActions(CollectionUtils.asArrayList(a3)); + RulesEngine.instance().dao().putRule(r3); + + Rule r4 = new Rule(); + r4.setAccountId(100); + Criteria c4 = new Criteria(); + c4.setType(EventType.SWITCH_LEVEL); + c4.setSourceId("204"); + c4.setOperator(Operator.EQUAL); + c4.setValue(0); + r4.setCriteria(CollectionUtils.asArrayList(c4)); + Action a4 = new Action(); + a4.setType(ActionType.MOBILE_ALERT_STATIC); + a4.setDescription("Garage Door 2 closed"); + a4.setDestinationId("*"); + r4.setActions(CollectionUtils.asArrayList(a4)); + RulesEngine.instance().dao().putRule(r4); + + Rule r5 = new Rule(); + r5.setAccountId(100); + Criteria c5 = new Criteria(); + c5.setType(EventType.SWITCH_LEVEL); + c5.setSourceId("205"); + c5.setOperator(Operator.EQUAL); + c5.setValue(1); + r5.setCriteria(CollectionUtils.asArrayList(c5)); + Action a5 = new Action(); + a5.setType(ActionType.MOBILE_ALERT_STATIC); + a5.setDescription("Garage Door 3 opened"); + a5.setDestinationId("*"); + r5.setActions(CollectionUtils.asArrayList(a5)); + RulesEngine.instance().dao().putRule(r5); + + Rule r6 = new Rule(); + r6.setAccountId(100); + Criteria c6 = new Criteria(); + c6.setType(EventType.SWITCH_LEVEL); + c6.setSourceId("205"); + c6.setOperator(Operator.EQUAL); + c6.setValue(0); + r6.setCriteria(CollectionUtils.asArrayList(c6)); + Action a6 = new Action(); + a6.setType(ActionType.MOBILE_ALERT_STATIC); + a6.setDescription("Garage Door 3 closed"); + a6.setDestinationId("*"); + r6.setActions(CollectionUtils.asArrayList(a6)); + RulesEngine.instance().dao().putRule(r6); + + Rule r7 = new Rule(); + r7.setAccountId(100); + Criteria c7 = new Criteria(); + c7.setType(EventType.SWITCH_LEVEL); + c7.setSourceId("203"); + c7.setOperator(Operator.EQUAL); + c7.setValue(1); + Criteria c7_2 = new Criteria(); + c7_2.setType(EventType.TIME); + c7_2.setValue(79200); +// c7_2.setValue(74400); + r7.setCriteria(CollectionUtils.asArrayList(c7, c7_2)); + Action a7 = new Action(); + a7.setType(ActionType.MOBILE_ALERT_STATIC); + a7.setDescription("Garage Door 1 is still open"); + a7.setDestinationId("*"); + r7.setActions(CollectionUtils.asArrayList(a7)); + RulesEngine.instance().dao().putRule(r7); + + Rule r8 = new Rule(); + r8.setAccountId(100); + Criteria c8 = new Criteria(); + c8.setType(EventType.SWITCH_LEVEL); + c8.setSourceId("204"); + c8.setOperator(Operator.EQUAL); + c8.setValue(1); + Criteria c8_2 = new Criteria(); + c8_2.setType(EventType.TIME); + c8_2.setValue(79200); +// c8_2.setValue(74400); + r8.setCriteria(CollectionUtils.asArrayList(c8, c8_2)); + Action a8 = new Action(); + a8.setType(ActionType.MOBILE_ALERT_STATIC); + a8.setDescription("Garage Door 2 is still open"); + a8.setDestinationId("*"); + r8.setActions(CollectionUtils.asArrayList(a8)); + RulesEngine.instance().dao().putRule(r8); + + Rule r9 = new Rule(); + r9.setAccountId(100); + Criteria c9 = new Criteria(); + c9.setType(EventType.SWITCH_LEVEL); + c9.setSourceId("205"); + c9.setOperator(Operator.EQUAL); + c9.setValue(1); + Criteria c9_2 = new Criteria(); + c9_2.setType(EventType.TIME); + c9_2.setValue(79200); +// c9_2.setValue(74400); + r9.setCriteria(CollectionUtils.asArrayList(c9, c9_2)); + Action a9 = new Action(); + a9.setType(ActionType.MOBILE_ALERT_STATIC); + a9.setDescription("Garage Door 3 is still open"); + a9.setDestinationId("*"); + r9.setActions(CollectionUtils.asArrayList(a9)); + RulesEngine.instance().dao().putRule(r9); + RulesEngine.shutdown(); + } +} diff --git a/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestRuleSchedule.java b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestRuleSchedule.java new file mode 100644 index 0000000..df3c739 --- /dev/null +++ b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestRuleSchedule.java @@ -0,0 +1,23 @@ +package com.lanternsoftware; + +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.datamodel.rules.Rule; +import com.lanternsoftware.rules.RulesEngine; +import com.lanternsoftware.util.CollectionUtils; + +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +public class TestRuleSchedule { + public static void main(String[] args) { + TimeZone tz = TimeZone.getTimeZone("America/Chicago"); //TODO: Get from the current monitor account + List rules = CollectionUtils.filter(RulesEngine.instance().dao().getRulesForAccount(100), _r->CollectionUtils.anyQualify(_r.getAllCriteria(), _c->_c.getType() == EventType.TIME)); + if (rules.isEmpty()) + return; + Collection dates = CollectionUtils.aggregate(rules, _r->CollectionUtils.transform(_r.getAllCriteria(), _c->_c.getNextTriggerDate(tz), true)); + Date nextDate = CollectionUtils.getSmallest(dates); + + } +} diff --git a/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestSendAlert.java b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestSendAlert.java new file mode 100644 index 0000000..7082f64 --- /dev/null +++ b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestSendAlert.java @@ -0,0 +1,36 @@ +package com.lanternsoftware; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Message; +import com.lanternsoftware.dataaccess.rules.MongoRulesDataAccess; +import com.lanternsoftware.dataaccess.rules.RulesDataAccess; +import com.lanternsoftware.datamodel.rules.Alert; +import com.lanternsoftware.datamodel.rules.FcmDevice; +import com.lanternsoftware.util.LanternFiles; +import com.lanternsoftware.util.dao.DaoSerializer; +import com.lanternsoftware.util.dao.mongo.MongoConfig; +import org.apache.commons.io.IOUtils; + +import java.io.FileInputStream; + +public class TestSendAlert { + public static void main(String[] args) { + RulesDataAccess dao = new MongoRulesDataAccess(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg")); + for (FcmDevice d : dao.getFcmDevicesForAccount(100)) { + Alert alert = new Alert(); + alert.setMessage("Test Alert"); + Message msg = Message.builder().setToken(d.getToken()).putData("payload", DaoSerializer.toBase64ZipBson(alert)).putData("payloadClass", Alert.class.getCanonicalName()).build(); + try { + FileInputStream is = new FileInputStream("d:\\zwave\\firebase\\account_key.json"); + FirebaseOptions options = FirebaseOptions.builder().setCredentials(GoogleCredentials.fromStream(is)).build(); + FirebaseMessaging.getInstance(FirebaseApp.initializeApp(options)).send(msg); + IOUtils.closeQuietly(is); + } catch (Exception _e) { + _e.printStackTrace(); + } + } + } +} diff --git a/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestTimeRule.java b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestTimeRule.java new file mode 100644 index 0000000..ace8c26 --- /dev/null +++ b/rules/lantern-service-rules/src/test/java/com/lanternsoftware/TestTimeRule.java @@ -0,0 +1,21 @@ +package com.lanternsoftware; + +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.rules.RulesEngine; +import com.lanternsoftware.util.DateUtils; +import com.lanternsoftware.util.concurrency.ConcurrencyUtils; + +import java.util.TimeZone; + +public class TestTimeRule { + public static void main(String[] args) { + Event event = new Event(); + event.setAccountId(100); + event.setTime(DateUtils.date(7, 15, 2021, 18, 30, 0, 0, TimeZone.getTimeZone("America/Chicago"))); + event.setType(EventType.TIME); + RulesEngine.instance().fireEvent(event); + ConcurrencyUtils.sleep(200000); + RulesEngine.shutdown(); + } +} diff --git a/rules/pom.xml b/rules/pom.xml new file mode 100644 index 0000000..47c9545 --- /dev/null +++ b/rules/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + pom + com.lanternsoftware.rules + rules-reactor + rules-reactor + 1.0.0 + + + 1.8 + 1.8 + + + + lantern-dataaccess-rules + lantern-datamodel-rules + lantern-service-rules + + \ No newline at end of file diff --git a/util/lantern-util-common/src/main/java/com/lanternsoftware/util/CollectionUtils.java b/util/lantern-util-common/src/main/java/com/lanternsoftware/util/CollectionUtils.java index 5333a12..0bc70f1 100644 --- a/util/lantern-util-common/src/main/java/com/lanternsoftware/util/CollectionUtils.java +++ b/util/lantern-util-common/src/main/java/com/lanternsoftware/util/CollectionUtils.java @@ -532,7 +532,6 @@ public class CollectionUtils { return list; } - public static void edit(Iterable _coll, IEditor _editor) { if ((_coll == null) || (_editor == null)) return; diff --git a/util/lantern-util-common/src/main/java/com/lanternsoftware/util/LanternFiles.java b/util/lantern-util-common/src/main/java/com/lanternsoftware/util/LanternFiles.java index 340ca77..c4d5f47 100644 --- a/util/lantern-util-common/src/main/java/com/lanternsoftware/util/LanternFiles.java +++ b/util/lantern-util-common/src/main/java/com/lanternsoftware/util/LanternFiles.java @@ -1,8 +1,11 @@ package com.lanternsoftware.util; public abstract class LanternFiles { - public static final String SOURCE_PATH = "C:\\lantern\\wc\\opensource\\LanternPowerMonitor\\"; - public static final String OPS_PATH = "D:\\zwave\\"; -// public static final String OPS_PATH = "D:\\zwave\\linux\\"; -// public static final String OPS_PATH = "/opt/tomcat/"; + public static final String SOURCE_PATH = "C:\\lantern\\LanternPowerMonitor\\"; +// public static final String OPS_PATH = "D:\\zwave\\"; +// public static final String OPS_PATH = "D:\\zwave\\localhost\\"; +// public static final String OPS_PATH = "D:\\zwave\\mark4770\\"; +// public static final String OPS_PATH = "D:\\zwave\\prod\\"; +// public static final String OPS_PATH = "D:\\zwave\\prodremote\\"; + public static final String OPS_PATH = "/opt/tomcat/"; } diff --git a/util/lantern-util-common/src/main/java/com/lanternsoftware/util/cryptography/AESTool.java b/util/lantern-util-common/src/main/java/com/lanternsoftware/util/cryptography/AESTool.java index b1c8b83..c4e9a18 100644 --- a/util/lantern-util-common/src/main/java/com/lanternsoftware/util/cryptography/AESTool.java +++ b/util/lantern-util-common/src/main/java/com/lanternsoftware/util/cryptography/AESTool.java @@ -17,6 +17,8 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; +import com.lanternsoftware.util.LanternFiles; +import com.lanternsoftware.util.ResourceLoader; import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,6 +78,10 @@ public class AESTool { System.out.println(builder.toString()); } + public static AESTool authTool() { + return new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat")); + } + /** * @param _btKey the encoded form of a {@link SecretKey} object. See the {@link SecretKey#getEncoded()} method. */ diff --git a/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/MongoProxy.java b/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/MongoProxy.java index 7b736e3..f46dc40 100644 --- a/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/MongoProxy.java +++ b/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/MongoProxy.java @@ -71,6 +71,8 @@ public class MongoProxy extends AbstractDaoProxy { public MongoProxy(List _hosts, String _userName, String _password, String _clientKeystorePath, String _clientKeystorePassword, String _caKeystorePath, String _caKeystorePassword, String _dbName, String _authDbName) { List listAddresses = new LinkedList<>(); + if (CollectionUtils.isEmpty(_hosts)) + _hosts = CollectionUtils.asArrayList("localhost"); for (String addr : _hosts) { int portIdx = addr.indexOf(":"); if (portIdx > 0) @@ -108,7 +110,7 @@ public class MongoProxy extends AbstractDaoProxy { options = MongoClientOptions.builder().sslEnabled(false).build(); } } - client = new MongoClient(listAddresses, MongoCredential.createCredential(_userName, NullUtils.isNotEmpty(_authDbName) ? _authDbName : "admin", _password.toCharArray()), options); + client = NullUtils.isEmpty(_userName) ? new MongoClient(listAddresses, options) : new MongoClient(listAddresses, MongoCredential.createCredential(_userName, NullUtils.isNotEmpty(_authDbName) ? _authDbName : "admin", _password.toCharArray()), options); dbName = _dbName; } diff --git a/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/dao/MongoConfigSerializer.java b/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/dao/MongoConfigSerializer.java index b615123..746c513 100644 --- a/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/dao/MongoConfigSerializer.java +++ b/util/lantern-util-dao-mongo/src/main/java/com/lanternsoftware/util/dao/mongo/dao/MongoConfigSerializer.java @@ -1,13 +1,13 @@ package com.lanternsoftware.util.dao.mongo.dao; -import com.lanternsoftware.util.CollectionUtils; -import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.dao.AbstractDaoSerializer; import com.lanternsoftware.util.dao.DaoEntity; +import com.lanternsoftware.util.dao.DaoProxyType; import com.lanternsoftware.util.dao.DaoSerializer; - import com.lanternsoftware.util.dao.mongo.MongoConfig; - +import java.lang.String; +import java.util.Collections; +import java.util.List; public class MongoConfigSerializer extends AbstractDaoSerializer { @@ -17,11 +17,16 @@ public class MongoConfigSerializer extends AbstractDaoSerializer return MongoConfig.class; } + @Override + public List getSupportedProxies() { + return Collections.singletonList(DaoProxyType.MONGO); + } + @Override public DaoEntity toDaoEntity(MongoConfig _o) { DaoEntity d = new DaoEntity(); - d.put("hosts", CollectionUtils.commaSeparated(_o.getHosts())); + d.put("hosts", _o.getHosts()); d.put("username", _o.getUsername()); d.put("password", _o.getPassword()); d.put("client_keystore_path", _o.getClientKeystorePath()); @@ -37,7 +42,7 @@ public class MongoConfigSerializer extends AbstractDaoSerializer public MongoConfig fromDaoEntity(DaoEntity _d) { MongoConfig o = new MongoConfig(); - o.setHosts(CollectionUtils.asArrayList(NullUtils.cleanSplit(DaoSerializer.getString(_d, "hosts"), ","))); + o.setHosts(DaoSerializer.getList(_d, "hosts", String.class)); o.setUsername(DaoSerializer.getString(_d, "username")); o.setPassword(DaoSerializer.getString(_d, "password")); o.setClientKeystorePath(DaoSerializer.getString(_d, "client_keystore_path")); diff --git a/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/DaoSerializer.java b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/DaoSerializer.java index 3ed9a3b..e060935 100644 --- a/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/DaoSerializer.java +++ b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/DaoSerializer.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.ServiceLoader; import java.util.Set; +import org.apache.commons.codec.binary.Base64; import org.bson.BsonBinaryReader; import org.bson.BsonBinaryWriter; import org.bson.Document; @@ -725,6 +726,14 @@ public class DaoSerializer { return ZipUtils.zip(toBson(_entity, true)); } + public static String toBase64ZipBson(Object _o) { + return toBase64ZipBson(toDaoEntity(_o)); + } + + public static String toBase64ZipBson(DaoEntity _entity) { + return Base64.encodeBase64String(toZipBson(_entity)); + } + public static T fromZipBson(byte[] _btZipBson, Class _class) { return DaoSerializer.fromDaoEntity(fromZipBson(_btZipBson), _class); } @@ -733,6 +742,14 @@ public class DaoSerializer { return fromBson(ZipUtils.unzip(_btZipBson)); } + public static T fromBase64ZipBson(String _zipBson, Class _class) { + return DaoSerializer.fromDaoEntity(fromBase64ZipBson(_zipBson), _class); + } + + public static DaoEntity fromBase64ZipBson(String _zipBson) { + return fromBson(ZipUtils.unzip(Base64.decodeBase64(_zipBson))); + } + public static T fromBson(byte[] _btBson, Class _class) { return fromDaoEntity(fromBson(_btBson), _class); } diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/AuthCode.java b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/auth/AuthCode.java similarity index 95% rename from currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/AuthCode.java rename to util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/auth/AuthCode.java index fd5bf04..6f76879 100644 --- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/AuthCode.java +++ b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/auth/AuthCode.java @@ -1,4 +1,4 @@ -package com.lanternsoftware.datamodel.currentmonitor; +package com.lanternsoftware.util.dao.auth; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.dao.annotations.DBSerializable; diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/AuthCodeSerializer.java b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/auth/dao/AuthCodeSerializer.java similarity index 86% rename from currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/AuthCodeSerializer.java rename to util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/auth/dao/AuthCodeSerializer.java index f0afb65..bbbe20f 100644 --- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/AuthCodeSerializer.java +++ b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/auth/dao/AuthCodeSerializer.java @@ -1,14 +1,12 @@ -package com.lanternsoftware.datamodel.currentmonitor.dao; +package com.lanternsoftware.util.dao.auth.dao; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.dao.AbstractDaoSerializer; import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoProxyType; import com.lanternsoftware.util.dao.DaoSerializer; -import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/jdbc/dao/JdbcConfigSerializer.java b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/jdbc/dao/JdbcConfigSerializer.java index 9df69ad..ecb3645 100644 --- a/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/jdbc/dao/JdbcConfigSerializer.java +++ b/util/lantern-util-dao/src/main/java/com/lanternsoftware/util/dao/jdbc/dao/JdbcConfigSerializer.java @@ -6,7 +6,6 @@ import com.lanternsoftware.util.dao.DaoProxyType; import com.lanternsoftware.util.dao.DaoSerializer; import com.lanternsoftware.util.dao.jdbc.DatabaseType; import com.lanternsoftware.util.dao.jdbc.JdbcConfig; - import java.util.Collections; import java.util.List; diff --git a/util/lantern-util-dao/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer b/util/lantern-util-dao/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer index 6043f50..7b0b660 100644 --- a/util/lantern-util-dao/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer +++ b/util/lantern-util-dao/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer @@ -1 +1,2 @@ +com.lanternsoftware.util.dao.auth.dao.AuthCodeSerializer com.lanternsoftware.util.dao.jdbc.dao.JdbcConfigSerializer diff --git a/util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/FreemarkerServlet.java b/util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/FreemarkerServlet.java index d3e072c..24fa490 100644 --- a/util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/FreemarkerServlet.java +++ b/util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/FreemarkerServlet.java @@ -3,172 +3,79 @@ package com.lanternsoftware.util.servlet; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.dao.DaoEntity; -import com.lanternsoftware.util.dao.DaoSerializer; import freemarker.template.Configuration; -import org.apache.commons.io.IOUtils; import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.MediaType; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.HashMap; import java.util.Map; -public abstract class FreemarkerServlet extends HttpServlet { - protected abstract Configuration getFreemarkerConfig(); - - public static String[] getPath(HttpServletRequest _request) { - String sPath = _request.getRequestURI().substring(_request.getContextPath().length()); - if (sPath.startsWith("/")) - sPath = sPath.substring(1); - String[] path = sPath.split("/"); - if ((path.length == 0) || (path[0].length() == 0)) - return new String[] { "index" }; - int iExtPos = CollectionUtils.last(path).lastIndexOf("."); - if (iExtPos > -1) { - path[path.length - 1] = CollectionUtils.last(path).substring(0, iExtPos); - } - return path; - } - - public static void redirect(HttpServletResponse _response, String _sURL) throws IOException { - _response.sendRedirect(_response.encodeRedirectURL(_sURL)); - } - - public void render(HttpServletResponse _rep, String _sHtmlResourceKey, Map _mapModel) { - String html = FreemarkerUtil.render(getFreemarkerConfig(), _sHtmlResourceKey, _mapModel); - if (html == null) - _rep.setStatus(500); - else - setResponseHtml(_rep, html); - } +public abstract class FreemarkerServlet extends LanternServlet { + protected abstract Configuration getFreemarkerConfig(); - public static DaoEntity model(HttpServletRequest _req, String _name, Object _value) { - DaoEntity model = model(_req); - model.put(_name, _value); - return model; - } + public static String[] getPath(HttpServletRequest _request) { + String sPath = _request.getRequestURI().substring(_request.getContextPath().length()); + if (sPath.startsWith("/")) + sPath = sPath.substring(1); + String[] path = sPath.split("/"); + if ((path.length == 0) || (path[0].length() == 0)) + return new String[]{"index"}; + int iExtPos = CollectionUtils.last(path).lastIndexOf("."); + if (iExtPos > -1) { + path[path.length - 1] = CollectionUtils.last(path).substring(0, iExtPos); + } + return path; + } - protected static DaoEntity model(HttpServletRequest _req) { - DaoEntity model = new DaoEntity("context", _req.getContextPath()); - model.put("css_version", "1.0.0"); - return model; - } + public static void redirect(HttpServletResponse _response, String _sURL) throws IOException { + _response.sendRedirect(_response.encodeRedirectURL(_sURL)); + } - public static T getSessionVar(HttpServletRequest _req, String _name) { - return (T) _req.getSession().getAttribute(_name); - } + public void render(HttpServletResponse _rep, String _sHtmlResourceKey, Map _mapModel) { + String html = FreemarkerUtil.render(getFreemarkerConfig(), _sHtmlResourceKey, _mapModel); + if (html == null) + _rep.setStatus(500); + else + setResponseHtml(_rep, html); + } - public static void putSessionVar(HttpServletRequest _req, String _name, Object _var) { - _req.getSession().setAttribute(_name, _var); - } + public static DaoEntity model(HttpServletRequest _req, String _name, Object _value) { + DaoEntity model = model(_req); + model.put(_name, _value); + return model; + } - protected String relativeOffset(HttpServletRequest _req) { - String[] path = getPath(_req); - StringBuilder offset = new StringBuilder(); - for (int i = 1; i < CollectionUtils.size(path); i++) { - offset.append("../"); - } - return offset.toString(); - } - - protected Cookie getCookie(HttpServletRequest _req, String _name) { - if (_req.getCookies() != null) { - for (Cookie c : _req.getCookies()) { - if (NullUtils.isEqual(c.getName(), _name)) - return c; - } - } - return null; - } + protected static DaoEntity model(HttpServletRequest _req) { + DaoEntity model = new DaoEntity("context", _req.getContextPath()); + model.put("css_version", "1.0.0"); + return model; + } - public static void setResponseHtml(HttpServletResponse _response, String _sHtml) { - setResponseEntity(_response, MediaType.TEXT_HTML, _sHtml); - } + public static T getSessionVar(HttpServletRequest _req, String _name) { + return (T) _req.getSession().getAttribute(_name); + } - public static void setResponseEntity(HttpServletResponse _response, String _sContentType, String _sEntity) { - setResponseEntity(_response, 200, _sContentType, _sEntity); - } + public static void putSessionVar(HttpServletRequest _req, String _name, Object _var) { + _req.getSession().setAttribute(_name, _var); + } - public static void setResponseEntity(HttpServletResponse _response, String _sContentType, byte[] _btData) { - setResponseEntity(_response, 200, _sContentType, _btData); - } - - public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, String _sEntity) { - setResponseEntity(_response, _iStatus, _sContentType, NullUtils.toByteArray(_sEntity)); - } - - public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, byte[] _btData) { - OutputStream os = null; - try { - _response.setStatus(_iStatus); - _response.setCharacterEncoding("UTF-8"); - _response.setContentType(_sContentType); - if ((_btData != null) && (_btData.length > 0)) { - _response.setContentLength(_btData.length); - os = _response.getOutputStream(); - os.write(_btData); - } else - _response.setContentLength(0); - } catch (Exception e) { - e.printStackTrace(); - } finally { - IOUtils.closeQuietly(os); - } - } - - protected void zipBsonResponse(HttpServletResponse _response, Object _object) - { - setResponseEntity(_response, 200, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(_object)); - } - - protected void jsonResponse(HttpServletResponse _response, Object _object) - { - setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, DaoSerializer.toJson(_object)); - } - - protected void jsonResponse(HttpServletResponse _response, String _json) - { - setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, _json); - } - - protected String getRequestPayloadAsString(HttpServletRequest _req) { - return NullUtils.toString(getRequestPayload(_req)); - } - - protected byte[] getRequestPayload(HttpServletRequest _req) { - InputStream is = null; - try { - is = _req.getInputStream(); - return IOUtils.toByteArray(is); - } - catch (Exception e) { - e.printStackTrace(); - return null; - } - finally { - IOUtils.closeQuietly(is); - } - } - - protected DaoEntity getRequestZipBson(HttpServletRequest _req) { - return DaoSerializer.fromZipBson(getRequestPayload(_req)); - } - - protected T getRequestPayload(HttpServletRequest _req, Class _retClass) { - return DaoSerializer.fromZipBson(getRequestPayload(_req), _retClass); - } - - protected String[] path(HttpServletRequest _req) { - return NullUtils.cleanSplit(NullUtils.makeNotNull(_req.getPathInfo()), "/"); - } - - protected boolean isPath(HttpServletRequest _req, int _index, String _path) { - return NullUtils.isEqual(_path, CollectionUtils.get(path(_req), _index)); - } + protected String relativeOffset(HttpServletRequest _req) { + String[] path = getPath(_req); + StringBuilder offset = new StringBuilder(); + for (int i = 1; i < CollectionUtils.size(path); i++) { + offset.append("../"); + } + return offset.toString(); + } + protected Cookie getCookie(HttpServletRequest _req, String _name) { + if (_req.getCookies() != null) { + for (Cookie c : _req.getCookies()) { + if (NullUtils.isEqual(c.getName(), _name)) + return c; + } + } + return null; + } } diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CMServlet.java b/util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/LanternServlet.java similarity index 96% rename from currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CMServlet.java rename to util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/LanternServlet.java index ccc1bfd..348a4bf 100644 --- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/CMServlet.java +++ b/util/lantern-util-servlet/src/main/java/com/lanternsoftware/util/servlet/LanternServlet.java @@ -1,4 +1,4 @@ -package com.lanternsoftware.currentmonitor.servlet; +package com.lanternsoftware.util.servlet; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.NullUtils; @@ -13,7 +13,7 @@ import javax.ws.rs.core.MediaType; import java.io.InputStream; import java.io.OutputStream; -public abstract class CMServlet extends HttpServlet { +public abstract class LanternServlet extends HttpServlet { public static void setResponseHtml(HttpServletResponse _response, String _sHtml) { setResponseEntity(_response, MediaType.TEXT_HTML, _sHtml); } diff --git a/zwave/lantern-datamodel-zwave/pom.xml b/zwave/lantern-datamodel-zwave/pom.xml index ca1fe14..a7e0089 100644 --- a/zwave/lantern-datamodel-zwave/pom.xml +++ b/zwave/lantern-datamodel-zwave/pom.xml @@ -1,6 +1,6 @@ 4.0.0 - com.lanternsoftware.services + com.lanternsoftware.zwave lantern-datamodel-zwave jar 1.0.0 diff --git a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/Switch.java b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/Switch.java index 5aca90e..426911e 100644 --- a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/Switch.java +++ b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/Switch.java @@ -154,6 +154,14 @@ public class Switch { return type == SwitchType.RELAY; } + public boolean isRelayButton() { + return type == SwitchType.RELAY_BUTTON; + } + + public boolean isSecurity() { + return type == SwitchType.SECURITY; + } + public boolean isControlledBy(String _controllerUrl) { return NullUtils.isEqual(_controllerUrl, controllerUrl); } diff --git a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/SwitchType.java b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/SwitchType.java index e06e0b5..c1f1a60 100644 --- a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/SwitchType.java +++ b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/SwitchType.java @@ -7,5 +7,6 @@ public enum SwitchType { SPACE_HEATER_THERMOSTAT, THERMOMETER, RELAY, - SECURITY + SECURITY, + RELAY_BUTTON } diff --git a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/ZWaveConfig.java b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/ZWaveConfig.java index 86a4af2..b79b769 100644 --- a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/ZWaveConfig.java +++ b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/ZWaveConfig.java @@ -13,6 +13,7 @@ public class ZWaveConfig { private String commPort; private String url; private String masterUrl; + private String rulesUrl; private List switches; public int getAccountId() { @@ -47,6 +48,14 @@ public class ZWaveConfig { masterUrl = _masterUrl; } + public String getRulesUrl() { + return rulesUrl; + } + + public void setRulesUrl(String _rulesUrl) { + rulesUrl = _rulesUrl; + } + public List getSwitches() { return switches; } diff --git a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/SwitchSerializer.java b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/SwitchSerializer.java index 783d533..e7075ab 100644 --- a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/SwitchSerializer.java +++ b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/SwitchSerializer.java @@ -36,11 +36,11 @@ public class SwitchSerializer extends AbstractDaoSerializer d.put("gpio_pin", _o.getGpioPin()); d.put("primary", _o.isPrimary()); d.put("hold", _o.isHold()); + d.put("hidden", _o.isHidden()); d.put("thermometer_url", _o.getThermometerUrl()); d.put("controller_url", _o.getControllerUrl()); d.put("thermostat_mode", DaoSerializer.toEnumName(_o.getThermostatMode())); d.put("low_level", _o.getLowLevel()); - d.put("hidden", _o.isHidden()); d.put("schedule", DaoSerializer.toDaoEntities(_o.getSchedule(), DaoProxyType.MONGO)); return d; } @@ -57,11 +57,11 @@ public class SwitchSerializer extends AbstractDaoSerializer o.setGpioPin(DaoSerializer.getInteger(_d, "gpio_pin")); o.setPrimary(DaoSerializer.getBoolean(_d, "primary")); o.setHold(DaoSerializer.getBoolean(_d, "hold")); + o.setHidden(DaoSerializer.getBoolean(_d, "hidden")); o.setThermometerUrl(DaoSerializer.getString(_d, "thermometer_url")); o.setControllerUrl(DaoSerializer.getString(_d, "controller_url")); o.setThermostatMode(DaoSerializer.getEnum(_d, "thermostat_mode", ThermostatMode.class)); o.setLowLevel(DaoSerializer.getInteger(_d, "low_level")); - o.setHidden(DaoSerializer.getBoolean(_d, "hidden")); o.setSchedule(DaoSerializer.getList(_d, "schedule", SwitchSchedule.class)); return o; } diff --git a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/ZWaveConfigSerializer.java b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/ZWaveConfigSerializer.java index 9fb7bad..93e1614 100644 --- a/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/ZWaveConfigSerializer.java +++ b/zwave/lantern-datamodel-zwave/src/main/java/com/lanternsoftware/datamodel/zwave/dao/ZWaveConfigSerializer.java @@ -31,6 +31,7 @@ public class ZWaveConfigSerializer extends AbstractDaoSerializer d.put("comm_port", _o.getCommPort()); d.put("url", _o.getUrl()); d.put("master_url", _o.getMasterUrl()); + d.put("rules_url", _o.getRulesUrl()); d.put("switches", DaoSerializer.toDaoEntities(_o.getSwitches(), DaoProxyType.MONGO)); return d; } @@ -43,6 +44,7 @@ public class ZWaveConfigSerializer extends AbstractDaoSerializer o.setCommPort(DaoSerializer.getString(_d, "comm_port")); o.setUrl(DaoSerializer.getString(_d, "url")); o.setMasterUrl(DaoSerializer.getString(_d, "master_url")); + o.setRulesUrl(DaoSerializer.getString(_d, "rules_url")); o.setSwitches(DaoSerializer.getList(_d, "switches", Switch.class)); return o; } diff --git a/zwave/lantern-service-zwave/pom.xml b/zwave/lantern-service-zwave/pom.xml index fa4bdfb..06e808a 100644 --- a/zwave/lantern-service-zwave/pom.xml +++ b/zwave/lantern-service-zwave/pom.xml @@ -14,7 +14,7 @@ - com.lanternsoftware.services + com.lanternsoftware.zwave lantern-datamodel-zwave 1.0.0 @@ -33,6 +33,11 @@ lantern-zwave 1.0.0 + + com.lanternsoftware.rules + lantern-datamodel-rules + 1.0.0 + com.lanternsoftware.util lantern-util-dao-mongo diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java index 4957883..bd76c8f 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java @@ -1,6 +1,8 @@ package com.lanternsoftware.zwave.context; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.datamodel.rules.Event; +import com.lanternsoftware.datamodel.rules.EventType; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.zwave.Switch; import com.lanternsoftware.datamodel.zwave.SwitchSchedule; import com.lanternsoftware.datamodel.zwave.SwitchTransition; @@ -32,6 +34,7 @@ import com.lanternsoftware.zwave.message.impl.ThermostatSetPointReportRequest; import com.lanternsoftware.zwave.message.impl.ThermostatSetPointSetRequest; import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex; import com.lanternsoftware.zwave.relay.RelayController; +import com.lanternsoftware.zwave.security.SecurityController; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; @@ -39,6 +42,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -48,8 +52,8 @@ import java.util.Timer; import java.util.TimerTask; public class ZWaveApp { - public static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat")); - public static String authCode = aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(100, null))); + public static final AESTool aes = AESTool.authTool(); + public static String authCode; private static final Logger logger = LoggerFactory.getLogger(ZWaveApp.class); @@ -57,6 +61,7 @@ public class ZWaveApp { private ZWaveConfig config; private Controller controller; private RelayController relayController; + private SecurityController securityController; private final Map originalSwitches = new HashMap<>(); private final Map switches = new HashMap<>(); private final Map mySwitches = new HashMap<>(); @@ -79,12 +84,14 @@ public class ZWaveApp { controller = new Controller(); controller.start(config.getCommPort()); } + authCode = aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(config.getAccountId(), null))); if (!config.isMaster()) { HttpGet get = new HttpGet(config.getMasterUrl() + "/config"); get.setHeader("auth_code", authCode); ZWaveConfig switchConfig = DaoSerializer.parse(pool.executeToString(get), ZWaveConfig.class); if (switchConfig != null) { config.setSwitches(switchConfig.getSwitches()); + config.setRulesUrl(switchConfig.getRulesUrl()); } else { logger.error("Failed to retrieve switch config from master controller"); @@ -125,6 +132,20 @@ public class ZWaveApp { if (CollectionUtils.anyQualify(mySwitches.values(), Switch::isRelay)) { relayController = new RelayController(); } + List securitySwitches = CollectionUtils.filter(mySwitches.values(), Switch::isSecurity); + if (!securitySwitches.isEmpty()) { + securityController = new SecurityController(); + for (Switch s : securitySwitches) { + s.setLevel(securityController.isOpen(s.getGpioPin())?1:0); + logger.info("Monitoring security sensor " + s.getFullDisplay() + " on gpio pin " + s.getGpioPin()); + securityController.listen(s, (_nodeId, _open) -> { + s.setLevel(_open?1:0); + logger.info(s.getFullDisplay() + " is " + ((s.getLevel() == 0)?"closed":"open")); + fireSwitchLevelEvent(s); + persistConfig(); + }); + } + } for (List group : groups.values()) { for (Switch sw : group) { peers.put(sw.getNodeId(), CollectionUtils.filter(group, _sw -> _sw.getNodeId() != sw.getNodeId())); @@ -161,6 +182,7 @@ public class ZWaveApp { if (sw != null) { if (NullUtils.isOneOf(_message.getIndex(), ThermostatSetPointIndex.HEATING, ThermostatSetPointIndex.COOLING)) { sw.setLevel((int) Math.round(_message.getTemperatureCelsius() * 1.8) + 32); + fireSwitchLevelEvent(sw); persistConfig(); } } @@ -222,6 +244,7 @@ public class ZWaveApp { if ((sw != null) && !sw.isPrimary()) { int newLevel = sw.isMultilevel()?_primaryLevel:((_primaryLevel == 0)?0:99); sw.setLevel(newLevel); + fireSwitchLevelEvent(sw); for (Switch peer : CollectionUtils.makeNotNull(peers.get(_secondaryNodeId))) { if (peer.isPrimary()) { logger.info("Mirror Event from node {} to node {}", _secondaryNodeId, peer.getNodeId()); @@ -254,22 +277,52 @@ public class ZWaveApp { nextScheduleTask = null; } + public int getAccountId() { + return config == null ? 0 : config.getAccountId(); + } + public void setSwitchLevel(int _nodeId, int _level) { setSwitchLevel(_nodeId, _level, true); } + public void fireSwitchLevelEvent(Switch _sw) { + if (NullUtils.isEmpty(config.getRulesUrl())) + return; + Event event = new Event(); + event.setEventDescription(_sw.getFullDisplay() + " set to " + _sw.getLevel()); + event.setType(EventType.SWITCH_LEVEL); + event.setTime(new Date()); + event.setValue(_sw.getLevel()); + event.setSourceId(String.valueOf(_sw.getNodeId())); + event.setAccountId(config.getAccountId()); + logger.info("Sending event to rules server - " + event.getEventDescription()); + HttpPost post = new HttpPost(NullUtils.terminateWith(config.getRulesUrl(), "/") + "event"); + post.setHeader("auth_code", authCode); + post.setEntity(new ByteArrayEntity(DaoSerializer.toZipBson(event))); + pool.execute(post); + } + public void setSwitchLevel(int _nodeId, int _level, boolean _updatePeers) { Switch sw = switches.get(_nodeId); if ((sw == null) || !sw.isPrimary()) return; sw.setLevel(_level); if (config.isMySwitch(sw)) { + fireSwitchLevelEvent(sw); if (sw.isSpaceHeaterThermostat()) { checkThermostat(sw); } else if (sw.isZWaveThermostat()) { controller.send(new ThermostatSetPointSetRequest((byte) sw.getNodeId(), sw.getThermostatMode() == ThermostatMode.COOL ? ThermostatSetPointIndex.COOLING : ThermostatSetPointIndex.HEATING, _level)); } else if (sw.isRelay()) { relayController.setRelay(sw.getGpioPin(), sw.getLevel() > 0); + } else if (sw.isRelayButton()) { + relayController.setRelay(sw.getGpioPin(), true); + timer.schedule(new TimerTask() { + @Override + public void run() { + relayController.setRelay(sw.getGpioPin(), false); + } + }, 250); } else { setGroupSwitchLevel(sw, _level); } @@ -331,7 +384,8 @@ public class ZWaveApp { } } if (_updatePeers) { - Set peers = CollectionUtils.transformToSet(modified, Switch::getControllerUrl); + Set peers = CollectionUtils.transformToSet(switches.values(), Switch::getControllerUrl); + peers.add(config.getMasterUrl()); peers.remove(config.getUrl()); for (String peer : peers) { for (Switch sw : modified) { @@ -354,11 +408,18 @@ public class ZWaveApp { } public void stop() { - controller.stop(); + if (controller != null) { + controller.stop(); + controller = null; + } if (relayController != null) { relayController.shutdown(); relayController = null; } + if (securityController != null) { + securityController.shutdown(); + securityController = null; + } if (timer != null) { timer.cancel(); timer = null; diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/ConfigServlet.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/ConfigServlet.java index af9995b..f8ddc78 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/ConfigServlet.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/ConfigServlet.java @@ -1,13 +1,11 @@ package com.lanternsoftware.zwave.servlet; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.zwave.context.Globals; -import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; @WebServlet("/config") public class ConfigServlet extends SecureServlet { diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SecureServlet.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SecureServlet.java index e8442cc..6e2074c 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SecureServlet.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SecureServlet.java @@ -1,9 +1,6 @@ package com.lanternsoftware.zwave.servlet; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; -import com.lanternsoftware.util.LanternFiles; -import com.lanternsoftware.util.ResourceLoader; -import com.lanternsoftware.util.cryptography.AESTool; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.dao.DaoSerializer; import com.lanternsoftware.zwave.context.Globals; import com.lanternsoftware.zwave.context.ZWaveApp; @@ -16,7 +13,7 @@ public abstract class SecureServlet extends ZWaveServlet { @Override protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { AuthCode authCode = DaoSerializer.fromZipBson(ZWaveApp.aes.decryptFromBase64(_req.getHeader("auth_code")), AuthCode.class); - if ((authCode == null) || (authCode.getAccountId() != 100)) { + if ((authCode == null) || (authCode.getAccountId() != Globals.app.getAccountId())) { _rep.setStatus(401); return; } @@ -29,7 +26,7 @@ public abstract class SecureServlet extends ZWaveServlet { @Override protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) { AuthCode authCode = DaoSerializer.fromZipBson(ZWaveApp.aes.decryptFromBase64(_req.getHeader("auth_code")), AuthCode.class); - if ((authCode == null) || (authCode.getAccountId() != 100)) { + if ((authCode == null) || (authCode.getAccountId() != Globals.app.getAccountId())) { _rep.setStatus(401); return; } diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SwitchServlet.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SwitchServlet.java index f427def..8593cbf 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SwitchServlet.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/SwitchServlet.java @@ -1,6 +1,6 @@ package com.lanternsoftware.zwave.servlet; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.datamodel.zwave.Switch; import com.lanternsoftware.datamodel.zwave.SwitchSchedule; import com.lanternsoftware.datamodel.zwave.ThermostatMode; diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/TemperatureServlet.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/TemperatureServlet.java index e81a563..d0118d6 100644 --- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/TemperatureServlet.java +++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/servlet/TemperatureServlet.java @@ -1,6 +1,6 @@ package com.lanternsoftware.zwave.servlet; -import com.lanternsoftware.datamodel.currentmonitor.AuthCode; +import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.dao.DaoEntity; diff --git a/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/GenerateSerializers.java b/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/GenerateSerializers.java index 4f2efee..9955450 100644 --- a/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/GenerateSerializers.java +++ b/zwave/lantern-service-zwave/src/test/java/com/lanternsoftware/zwave/GenerateSerializers.java @@ -6,6 +6,6 @@ import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator; public class GenerateSerializers { public static void main(String[] args) { - DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "zwave", true, null); + DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH, true, null); } } diff --git a/zwave/lantern-uirt/pom.xml b/zwave/lantern-uirt/pom.xml index 2aa546a..afee37e 100644 --- a/zwave/lantern-uirt/pom.xml +++ b/zwave/lantern-uirt/pom.xml @@ -1,6 +1,6 @@ 4.0.0 - com.lanternsoftware.services + com.lanternsoftware.zwave lantern-uirt jar 1.0.0