diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 2e895355b..000000000 --- a/.gitmodules +++ /dev/null @@ -1,12 +0,0 @@ -[submodule "ch.eitchnet.parent"] - path = ch.eitchnet.parent - url = https://github.com/eitchnet/ch.eitchnet.parent.git -[submodule "ch.eitchnet.utils"] - path = ch.eitchnet.utils - url = https://github.com/eitchnet/ch.eitchnet.utils.git -[submodule "ch.eitchnet.privilege"] - path = ch.eitchnet.privilege - url = https://github.com/eitchnet/ch.eitchnet.privilege.git -[submodule "ch.eitchnet.xmlpers"] - path = ch.eitchnet.xmlpers - url = https://github.com/eitchnet/ch.eitchnet.xmlpers.git diff --git a/README.md b/README.md index 83e6aedc8..76ec8f990 100644 --- a/README.md +++ b/README.md @@ -26,36 +26,4 @@ Find more to Strolch at our website: http://strolch.li Build status =================== -[![Build Status](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.parent/badge/icon)](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.parent/) ch.eitchnet.parent - -[![Build Status](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.privilege/badge/icon)](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.privilege/) ch.eitchnet.privilege - -[![Build Status](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.utils/badge/icon)](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.utils/) ch.eitchnet.utils - -[![Build Status](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.xmlpers/badge/icon)](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.xmlpers/) ch.eitchnet.xmlpers - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.model/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.model/) li.strolch.model - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.agent/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.agent/) li.strolch.agent - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.bom/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.bom/) li.strolch.bom - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.dev/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.dev/) li.strolch.dev - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.parent/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.parent/) li.strolch.parent - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.persistence.postgresql/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.persistence.postgresql/) li.strolch.persistence.postgresql - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.persistence.xml/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.persistence.xml/) li.strolch.persistence.xml - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.rest/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.rest/) li.strolch.rest - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.service/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.service/) li.strolch.service - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.testbase/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.testbase/) li.strolch.testbase - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.tutorialapp/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.tutorialapp/) li.strolch.tutorialapp - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.tutorialwebapp/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.tutorialwebapp/) li.strolch.tutorialwebapp - -[![Build Status](https://jenkins.eitchnet.ch/view/strolch/job/li.strolch.website/badge/icon)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.website/) li.strolch.website +[![Build Status](https://jenkins.eitchnet.ch/job/li.strolch/badge/icon)](https://jenkins.eitchnet.ch/job/li.strolch/) diff --git a/ch.eitchnet.parent b/ch.eitchnet.parent deleted file mode 160000 index 538fc3c44..000000000 --- a/ch.eitchnet.parent +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 538fc3c44956b57535c2c15fcf99b3602a22dd28 diff --git a/ch.eitchnet.privilege b/ch.eitchnet.privilege deleted file mode 160000 index 9b05d8cbb..000000000 --- a/ch.eitchnet.privilege +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9b05d8cbbd6bb6e176c0ae5bf3210c517a48fc93 diff --git a/ch.eitchnet.utils b/ch.eitchnet.utils deleted file mode 160000 index 49b325eca..000000000 --- a/ch.eitchnet.utils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 49b325eca13ffe7fe9cfc51ab964b8f7decc8522 diff --git a/ch.eitchnet.xmlpers b/ch.eitchnet.xmlpers deleted file mode 160000 index 4ba00c83d..000000000 --- a/ch.eitchnet.xmlpers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4ba00c83d661accb6a642d77ef0eda2ffc4ef4c3 diff --git a/li.strolch.agent/pom.xml b/li.strolch.agent/pom.xml index 576c1e92b..0d19a5381 100644 --- a/li.strolch.agent/pom.xml +++ b/li.strolch.agent/pom.xml @@ -1,34 +1,20 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.agent - li.strolch.agent Strolch Agent which is the runtime for Strolch - - https://github.com/eitchnet/li.strolch.agent - 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.agent/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - @@ -36,8 +22,8 @@ li.strolch.model - ch.eitchnet - ch.eitchnet.privilege + li.strolch + li.strolch.privilege commons-cli diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/AuditTrail.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/AuditTrail.java index eba9cdafe..b4bfdcf71 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/AuditTrail.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/AuditTrail.java @@ -21,7 +21,7 @@ import java.util.Set; import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/ComponentContainer.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/ComponentContainer.java index ccd113fb2..fba0a9c31 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/ComponentContainer.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/ComponentContainer.java @@ -18,9 +18,9 @@ package li.strolch.agent.api; import java.util.Set; import li.strolch.exception.StrolchException; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/RestrictableElement.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/RestrictableElement.java index 7a00c6067..af28a1ede 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/RestrictableElement.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/RestrictableElement.java @@ -15,7 +15,7 @@ */ package li.strolch.agent.api; -import ch.eitchnet.privilege.model.Restrictable; +import li.strolch.privilege.model.Restrictable; /** * A simple implementation for the {@link Restrictable} interface diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchAgent.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchAgent.java index 0a3abe6d5..1932956de 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchAgent.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchAgent.java @@ -25,11 +25,11 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.impl.ComponentContainerImpl; import li.strolch.runtime.configuration.ConfigurationParser; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.configuration.StrolchConfiguration; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchBootstrapper.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchBootstrapper.java index 53668a13d..cfec02c99 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchBootstrapper.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchBootstrapper.java @@ -12,12 +12,12 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.FileHelper; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.helper.XmlHelper; import li.strolch.runtime.configuration.ConfigurationParser; import li.strolch.runtime.configuration.StrolchConfigurationException; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.helper.XmlHelper; public class StrolchBootstrapper extends DefaultHandler { diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchComponent.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchComponent.java index 1733d8717..c47963824 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchComponent.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchComponent.java @@ -23,8 +23,8 @@ import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.SystemUserAction; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.SystemUserAction; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.privilege.RunRunnable; diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchRealm.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchRealm.java index 1bfa6bc56..cd878bf14 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchRealm.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchRealm.java @@ -18,7 +18,7 @@ package li.strolch.agent.api; import li.strolch.agent.impl.DataStoreMode; import li.strolch.model.StrolchRootElement; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java index 67090a76f..081544e67 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java @@ -17,7 +17,6 @@ package li.strolch.agent.impl; import java.util.List; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.agent.api.ActivityMap; import li.strolch.agent.api.AuditTrail; import li.strolch.agent.api.ElementMap; @@ -25,6 +24,7 @@ import li.strolch.model.ActivityVisitor; import li.strolch.model.activity.Activity; import li.strolch.model.query.ActivityQuery; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.utils.dbc.DBC; /** * This is the {@link AuditTrail} for {@link Activity Activities} diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingAuditMapFacade.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingAuditMapFacade.java index 51dc49be1..8b7d6e72c 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingAuditMapFacade.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingAuditMapFacade.java @@ -26,8 +26,8 @@ import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; import li.strolch.model.audit.AuditVisitor; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.dbc.DBC; /** *

diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java index cd42837fd..9df714f60 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java @@ -28,7 +28,7 @@ import li.strolch.model.StrolchRootElement; import li.strolch.model.parameter.StringListParameter; import li.strolch.model.parameter.StringParameter; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** *

diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java index 3b18390ea..618cba9e4 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java @@ -24,7 +24,7 @@ import li.strolch.model.Order; import li.strolch.model.OrderVisitor; import li.strolch.model.query.OrderQuery; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * This is the {@link AuditTrail} for {@link Order Orders} diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java index 7ee432312..6d1c4c8fd 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java @@ -24,7 +24,7 @@ import li.strolch.model.Resource; import li.strolch.model.ResourceVisitor; import li.strolch.model.query.ResourceQuery; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * This is the {@link AuditTrail} for {@link Resource Resources} diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedAuditTrail.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedAuditTrail.java index 97156fb6d..dfbc9fc6e 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedAuditTrail.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedAuditTrail.java @@ -25,12 +25,11 @@ import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.inmemory.InMemoryAuditDao; +import li.strolch.utils.collections.DateRange; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.collections.DateRange; - /** * @author Robert von Burg */ diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedRealm.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedRealm.java index b3384bbf8..b16d3afd8 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedRealm.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedRealm.java @@ -32,11 +32,11 @@ import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.configuration.ComponentConfiguration; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentContainerImpl.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentContainerImpl.java index a834dd44e..102e65197 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentContainerImpl.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentContainerImpl.java @@ -26,9 +26,6 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.helper.SystemHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.ComponentState; import li.strolch.agent.api.RealmHandler; @@ -36,11 +33,14 @@ import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.api.StrolchRealm; import li.strolch.exception.StrolchException; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.helper.SystemHelper; public class ComponentContainerImpl implements ComponentContainer { diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentDependencyAnalyzer.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentDependencyAnalyzer.java index ac174d22c..abbfba0ad 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentDependencyAnalyzer.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/ComponentDependencyAnalyzer.java @@ -23,13 +23,12 @@ import java.util.Set; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; - public class ComponentDependencyAnalyzer { private static final Logger logger = LoggerFactory.getLogger(ComponentDependencyAnalyzer.class); diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java index 0b25e83c5..3fd5ddd7b 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java @@ -25,12 +25,11 @@ import li.strolch.agent.api.LockHandler; import li.strolch.agent.api.StrolchLockException; import li.strolch.model.Locator; import li.strolch.model.StrolchRootElement; +import li.strolch.utils.dbc.DBC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.dbc.DBC; - /** * @author Robert von Burg */ diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultRealmHandler.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultRealmHandler.java index 14eb2fc05..a1f85c615 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultRealmHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultRealmHandler.java @@ -29,7 +29,7 @@ import li.strolch.exception.StrolchException; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/EmptyRealm.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/EmptyRealm.java index 9801b2368..17a70e1b1 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/EmptyRealm.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/EmptyRealm.java @@ -25,11 +25,11 @@ import li.strolch.agent.api.ResourceMap; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.inmemory.InMemoryPersistence; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/InternalStrolchRealm.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/InternalStrolchRealm.java index bba2e338a..cd02a7143 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/InternalStrolchRealm.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/InternalStrolchRealm.java @@ -27,15 +27,14 @@ import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; import li.strolch.agent.api.StrolchRealm; import li.strolch.model.StrolchRootElement; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; +import li.strolch.utils.dbc.DBC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; - /** * @author Robert von Burg */ diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/NoStrategyAuditTrail.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/NoStrategyAuditTrail.java index 0c0742cad..32f437bae 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/NoStrategyAuditTrail.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/NoStrategyAuditTrail.java @@ -22,7 +22,7 @@ import li.strolch.agent.api.AuditTrail; import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/StartRealms.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/StartRealms.java index 513fe7d2b..6c40f67fe 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/StartRealms.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/StartRealms.java @@ -15,8 +15,8 @@ */ package li.strolch.agent.impl; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalAuditTrail.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalAuditTrail.java index 077714a9a..503246c03 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalAuditTrail.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalAuditTrail.java @@ -23,7 +23,7 @@ import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalRealm.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalRealm.java index bd7cfd173..36cce26b0 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalRealm.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalRealm.java @@ -24,11 +24,11 @@ import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.configuration.ComponentConfiguration; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransientRealm.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransientRealm.java index 500aaa0d0..cfd6478a4 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransientRealm.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/TransientRealm.java @@ -18,10 +18,6 @@ package li.strolch.agent.impl; import java.io.File; import java.text.MessageFormat; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.ActivityMap; import li.strolch.agent.api.AuditTrail; import li.strolch.agent.api.ComponentContainer; @@ -32,9 +28,13 @@ import li.strolch.model.xml.XmlModelSaxFileReader; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.inmemory.InMemoryPersistence; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java index 95f950148..0b0447e22 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java @@ -26,12 +26,6 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.ExceptionHelper; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.ActivityMap; import li.strolch.agent.api.AuditTrail; import li.strolch.agent.api.ObserverHandler; @@ -69,9 +63,15 @@ import li.strolch.model.query.StrolchQuery; import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.IValue; import li.strolch.model.visitor.ElementTypeVisitor; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.service.api.Command; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.ExceptionHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AuditDao.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AuditDao.java index 78fc82b21..97f4202c7 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AuditDao.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AuditDao.java @@ -20,7 +20,7 @@ import java.util.Set; import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/PersistenceHandler.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/PersistenceHandler.java index eb52f4716..c10240026 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/PersistenceHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/PersistenceHandler.java @@ -24,7 +24,7 @@ import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.activity.Activity; import li.strolch.model.audit.Audit; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java index 9f57bb466..2e61afc80 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java @@ -17,7 +17,6 @@ package li.strolch.persistence.api; import java.util.List; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.agent.api.ActivityMap; import li.strolch.agent.api.AuditTrail; import li.strolch.agent.api.OrderMap; @@ -48,6 +47,7 @@ import li.strolch.model.parameter.StringParameter; import li.strolch.model.query.ActivityQuery; import li.strolch.model.query.OrderQuery; import li.strolch.model.query.ResourceQuery; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.service.api.Command; diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/TransactionResult.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/TransactionResult.java index 52126b64e..a3898de6d 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/TransactionResult.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/TransactionResult.java @@ -17,7 +17,7 @@ package li.strolch.persistence.api; import java.util.Date; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; public class TransactionResult { diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryAuditDao.java b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryAuditDao.java index 048d854e3..9ff2d7c91 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryAuditDao.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryAuditDao.java @@ -26,8 +26,8 @@ import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.AuditDao; import li.strolch.runtime.query.inmemory.InMemoryAuditQuery; import li.strolch.runtime.query.inmemory.InMemoryAuditQueryVisitor; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.collections.MapOfMaps; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.collections.MapOfMaps; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistence.java b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistence.java index 251da8939..d5a5fe089 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistence.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistence.java @@ -25,8 +25,8 @@ import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; public class InMemoryPersistence implements PersistenceHandler { diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistenceHandler.java b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistenceHandler.java index b702dfa43..2d09ce609 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistenceHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryPersistenceHandler.java @@ -24,8 +24,8 @@ import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.ComponentConfiguration; -import ch.eitchnet.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryTransaction.java index 8916f0c61..de9674fd0 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryTransaction.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryTransaction.java @@ -20,8 +20,8 @@ import li.strolch.persistence.api.AbstractTransaction; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.TransactionResult; import li.strolch.persistence.api.TransactionState; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; public class InMemoryTransaction extends AbstractTransaction { diff --git a/li.strolch.agent/src/main/java/li/strolch/policy/DefaultPolicyHandler.java b/li.strolch.agent/src/main/java/li/strolch/policy/DefaultPolicyHandler.java index 1fee9fa75..187939906 100644 --- a/li.strolch.agent/src/main/java/li/strolch/policy/DefaultPolicyHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/policy/DefaultPolicyHandler.java @@ -21,8 +21,6 @@ import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.Map; -import ch.eitchnet.utils.collections.MapOfMaps; -import ch.eitchnet.utils.helper.XmlHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.exception.StrolchPolicyException; @@ -34,6 +32,8 @@ import li.strolch.persistence.api.StrolchTransaction; import li.strolch.policy.StrolchPolicyFileParser.PolicyModel; import li.strolch.policy.StrolchPolicyFileParser.PolicyType; import li.strolch.runtime.configuration.ComponentConfiguration; +import li.strolch.utils.collections.MapOfMaps; +import li.strolch.utils.helper.XmlHelper; /** *

diff --git a/li.strolch.agent/src/main/java/li/strolch/policy/StrolchPolicyFileParser.java b/li.strolch.agent/src/main/java/li/strolch/policy/StrolchPolicyFileParser.java index dd5651e2e..bcdc1ca9c 100644 --- a/li.strolch.agent/src/main/java/li/strolch/policy/StrolchPolicyFileParser.java +++ b/li.strolch.agent/src/main/java/li/strolch/policy/StrolchPolicyFileParser.java @@ -22,7 +22,7 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/StrolchConstants.java b/li.strolch.agent/src/main/java/li/strolch/runtime/StrolchConstants.java index 461a5458a..286b5add3 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/StrolchConstants.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/StrolchConstants.java @@ -15,12 +15,12 @@ */ package li.strolch.runtime; -import static ch.eitchnet.utils.helper.StringHelper.DOT; +import static li.strolch.utils.helper.StringHelper.DOT; -import ch.eitchnet.privilege.handler.PrivilegeHandler; import li.strolch.agent.api.ObserverHandler; import li.strolch.model.StrolchModelConstants; import li.strolch.persistence.api.PersistenceHandler; +import li.strolch.privilege.handler.PrivilegeHandler; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/AbstractionConfiguration.java b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/AbstractionConfiguration.java index d82e81369..d618600fd 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/AbstractionConfiguration.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/AbstractionConfiguration.java @@ -24,7 +24,7 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; public abstract class AbstractionConfiguration { diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationParser.java b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationParser.java index bc86c2474..4e8ad34b7 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationParser.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationParser.java @@ -18,9 +18,9 @@ package li.strolch.runtime.configuration; import java.io.File; import java.text.MessageFormat; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.XmlHelper; import li.strolch.runtime.configuration.ConfigurationSaxParser.ConfigurationBuilder; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.XmlHelper; public class ConfigurationParser { diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationSaxParser.java b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationSaxParser.java index 8f057d2d7..929150585 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationSaxParser.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/ConfigurationSaxParser.java @@ -43,10 +43,10 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.model.Locator; import li.strolch.model.Locator.LocatorBuilder; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; public class ConfigurationSaxParser extends DefaultHandler { diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/DbConnectionBuilder.java b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/DbConnectionBuilder.java index ba8fd0180..2bb67e880 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/DbConnectionBuilder.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/DbConnectionBuilder.java @@ -15,10 +15,10 @@ */ package li.strolch.runtime.configuration; -import static ch.eitchnet.db.DbConstants.PROP_DB_IGNORE_REALM; -import static ch.eitchnet.db.DbConstants.PROP_DB_PASSWORD; -import static ch.eitchnet.db.DbConstants.PROP_DB_URL; -import static ch.eitchnet.db.DbConstants.PROP_DB_USERNAME; +import static li.strolch.db.DbConstants.PROP_DB_IGNORE_REALM; +import static li.strolch.db.DbConstants.PROP_DB_PASSWORD; +import static li.strolch.db.DbConstants.PROP_DB_URL; +import static li.strolch.db.DbConstants.PROP_DB_USERNAME; import static li.strolch.runtime.StrolchConstants.makeRealmKey; import java.sql.Connection; diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/StrolchEnvironment.java b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/StrolchEnvironment.java index 75428e28a..1feea9b64 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/StrolchEnvironment.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/configuration/StrolchEnvironment.java @@ -21,8 +21,8 @@ import java.text.MessageFormat; import java.util.Properties; import li.strolch.runtime.StrolchConstants; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/main/MainStarter.java b/li.strolch.agent/src/main/java/li/strolch/runtime/main/MainStarter.java index 7979a735f..bfdb763d6 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/main/MainStarter.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/main/MainStarter.java @@ -31,11 +31,11 @@ import org.apache.commons.cli.ParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchBootstrapper; import li.strolch.agent.api.StrolchVersion; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java index e6214ea29..ccbf07306 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java @@ -15,43 +15,43 @@ */ package li.strolch.runtime.privilege; -import static ch.eitchnet.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS; -import static ch.eitchnet.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH; +import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS; +import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH; import java.io.File; import java.io.FileInputStream; import java.text.MessageFormat; import java.util.Map; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.DefaultPrivilegeHandler; -import ch.eitchnet.privilege.handler.EncryptionHandler; -import ch.eitchnet.privilege.handler.PersistenceHandler; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.handler.XmlPersistenceHandler; -import ch.eitchnet.privilege.helper.PrivilegeInitializationHelper; -import ch.eitchnet.privilege.helper.XmlConstants; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel; -import ch.eitchnet.privilege.xml.PrivilegeConfigSaxReader; -import ch.eitchnet.utils.helper.XmlHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.api.StrolchRealm; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.DefaultPrivilegeHandler; +import li.strolch.privilege.handler.EncryptionHandler; +import li.strolch.privilege.handler.PersistenceHandler; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.handler.XmlPersistenceHandler; +import li.strolch.privilege.helper.PrivilegeInitializationHelper; +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.internal.PrivilegeContainerModel; +import li.strolch.privilege.xml.PrivilegeConfigSaxReader; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.RuntimeConfiguration; +import li.strolch.utils.helper.XmlHelper; public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements PrivilegeHandler { public static final String PROP_PRIVILEGE_CONFIG_FILE = "privilegeConfigFile"; //$NON-NLS-1$ public static final String PRIVILEGE_CONFIG_XML = "PrivilegeConfig.xml"; //$NON-NLS-1$ - private ch.eitchnet.privilege.handler.PrivilegeHandler privilegeHandler; + private li.strolch.privilege.handler.PrivilegeHandler privilegeHandler; public DefaultStrolchPrivilegeHandler(ComponentContainer container, String componentName) { super(container, componentName); @@ -65,7 +65,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements RuntimeConfiguration runtimeConfiguration = configuration.getRuntimeConfiguration(); File privilegeConfigFile = configuration.getConfigFile(PROP_PRIVILEGE_CONFIG_FILE, PRIVILEGE_CONFIG_XML, runtimeConfiguration); - ch.eitchnet.privilege.handler.PrivilegeHandler privilegeHandler = initializeFromXml(configuration, + li.strolch.privilege.handler.PrivilegeHandler privilegeHandler = initializeFromXml(configuration, privilegeConfigFile); this.privilegeHandler = privilegeHandler; } @@ -79,7 +79,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements * @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and * {@link PersistenceHandler} are set and initialized as well */ - private ch.eitchnet.privilege.handler.PrivilegeHandler initializeFromXml(ComponentConfiguration configuration, + private li.strolch.privilege.handler.PrivilegeHandler initializeFromXml(ComponentConfiguration configuration, File privilegeXmlFile) { // make sure file exists @@ -189,7 +189,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements } @Override - public ch.eitchnet.privilege.handler.PrivilegeHandler getPrivilegeHandler(Certificate certificate) + public li.strolch.privilege.handler.PrivilegeHandler getPrivilegeHandler(Certificate certificate) throws PrivilegeException { return this.privilegeHandler; } diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/PrivilegeHandler.java b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/PrivilegeHandler.java index d15cc8a02..9c543a99f 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/PrivilegeHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/PrivilegeHandler.java @@ -15,10 +15,10 @@ */ package li.strolch.runtime.privilege; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; /** * @author Robert von Burg @@ -30,28 +30,28 @@ public interface PrivilegeHandler { * @param password * @return * - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#authenticate(String, byte[]) + * @see li.strolch.privilege.handler.PrivilegeHandler#authenticate(String, byte[]) */ public abstract Certificate authenticate(String username, byte[] password); /** * @param certificate * @throws PrivilegeException - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#isCertificateValid(Certificate) + * @see li.strolch.privilege.handler.PrivilegeHandler#isCertificateValid(Certificate) */ public abstract void isCertificateValid(Certificate certificate) throws PrivilegeException; /** * @param certificate * @return - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#invalidateSession(ch.eitchnet.privilege.model.Certificate) + * @see li.strolch.privilege.handler.PrivilegeHandler#invalidateSession(li.strolch.privilege.model.Certificate) */ public abstract boolean invalidateSession(Certificate certificate); /** * @param certificate * @return - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#invalidateSession(ch.eitchnet.privilege.model.Certificate) + * @see li.strolch.privilege.handler.PrivilegeHandler#invalidateSession(li.strolch.privilege.model.Certificate) */ public abstract boolean sessionTimeout(Certificate certificate); @@ -59,7 +59,7 @@ public interface PrivilegeHandler { * @param certificate * @return * @throws PrivilegeException - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#getPrivilegeContext(ch.eitchnet.privilege.model.Certificate) + * @see li.strolch.privilege.handler.PrivilegeHandler#getPrivilegeContext(li.strolch.privilege.model.Certificate) */ public abstract PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException; @@ -67,8 +67,8 @@ public interface PrivilegeHandler { * @param systemUsername * @param action * @throws PrivilegeException - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#runAsSystem(java.lang.String, - * ch.eitchnet.privilege.handler.SystemUserAction) + * @see li.strolch.privilege.handler.PrivilegeHandler#runAsSystem(java.lang.String, + * li.strolch.privilege.handler.SystemUserAction) */ public abstract T runAsSystem(String systemUsername, T action) throws PrivilegeException; @@ -78,14 +78,14 @@ public interface PrivilegeHandler { * @return * @throws PrivilegeException */ - public abstract ch.eitchnet.privilege.handler.PrivilegeHandler getPrivilegeHandler(Certificate certificate) + public abstract li.strolch.privilege.handler.PrivilegeHandler getPrivilegeHandler(Certificate certificate) throws PrivilegeException; /** * @param certificate * @param password * @throws PrivilegeException - * @see {@link ch.eitchnet.privilege.handler.PrivilegeHandler#checkPassword(Certificate, byte[])} + * @see {@link li.strolch.privilege.handler.PrivilegeHandler#checkPassword(Certificate, byte[])} */ public void checkPassword(Certificate certificate, byte[] password) throws PrivilegeException; } \ No newline at end of file diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunAsAgent.java b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunAsAgent.java index 020846e6b..c46c0080d 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunAsAgent.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunAsAgent.java @@ -1,7 +1,7 @@ package li.strolch.runtime.privilege; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.service.api.AbstractService; import li.strolch.service.api.Service; import li.strolch.service.api.ServiceArgument; diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunRunnable.java b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunRunnable.java index 1022a06c3..5db3cda8c 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunRunnable.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/RunRunnable.java @@ -1,7 +1,7 @@ package li.strolch.runtime.privilege; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; /** * {@link SystemUserAction} to run {@link Runnable} as a system user diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/DefaultEnumHandler.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/DefaultEnumHandler.java index 1c6411f0c..d86f0e3b2 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/DefaultEnumHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/DefaultEnumHandler.java @@ -15,7 +15,7 @@ */ package li.strolch.runtime.query.enums; -import static ch.eitchnet.utils.helper.StringHelper.UNDERLINE; +import static li.strolch.utils.helper.StringHelper.UNDERLINE; import java.text.MessageFormat; import java.util.HashMap; @@ -31,10 +31,10 @@ import li.strolch.model.ParameterBag; import li.strolch.model.Resource; import li.strolch.model.parameter.StringParameter; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/EnumHandler.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/EnumHandler.java index 932ab2b92..a456dbe18 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/EnumHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/EnumHandler.java @@ -17,7 +17,7 @@ package li.strolch.runtime.query.enums; import java.util.Locale; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/StrolchEnum.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/StrolchEnum.java index dab3f9e8e..97a508a56 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/StrolchEnum.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/StrolchEnum.java @@ -30,7 +30,7 @@ import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/AuditTypeNavigator.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/AuditTypeNavigator.java index 91471dd55..d94ea7128 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/AuditTypeNavigator.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/AuditTypeNavigator.java @@ -19,8 +19,8 @@ import java.util.List; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.AuditDao; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/DateSelector.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/DateSelector.java index 7297eaa4b..e7529ca9a 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/DateSelector.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/DateSelector.java @@ -16,7 +16,7 @@ package li.strolch.runtime.query.inmemory; import li.strolch.model.Order; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/IdSelector.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/IdSelector.java index 22a644c71..07bc02aa7 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/IdSelector.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/IdSelector.java @@ -17,8 +17,8 @@ package li.strolch.runtime.query.inmemory; import java.util.List; -import ch.eitchnet.utils.StringMatchMode; import li.strolch.model.StrolchElement; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryVisitor.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryVisitor.java index 23940ea2a..244d0b844 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryVisitor.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryVisitor.java @@ -23,7 +23,7 @@ import li.strolch.model.query.ActivityQuery; import li.strolch.model.query.ActivityQueryVisitor; import li.strolch.model.query.StrolchTypeNavigation; import li.strolch.persistence.api.ActivityDao; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQuery.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQuery.java index 74f7a67d1..502151590 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQuery.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQuery.java @@ -21,7 +21,7 @@ import java.util.List; import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditVisitor; import li.strolch.persistence.inmemory.InMemoryAuditDao; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQueryVisitor.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQueryVisitor.java index 6c0b7b5d2..cd246901a 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQueryVisitor.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryAuditQueryVisitor.java @@ -24,8 +24,8 @@ import li.strolch.model.audit.AuditQueryVisitor; import li.strolch.model.audit.AuditVisitor; import li.strolch.model.audit.ElementSelection; import li.strolch.model.audit.IdentitySelection; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryVisitor.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryVisitor.java index 823f33eda..6c9c1f388 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryVisitor.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryVisitor.java @@ -25,7 +25,7 @@ import li.strolch.model.query.OrderQueryVisitor; import li.strolch.model.query.StateSelection; import li.strolch.model.query.StrolchTypeNavigation; import li.strolch.persistence.api.OrderDao; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQuery.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQuery.java index 9d430f305..a2788ce2f 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQuery.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQuery.java @@ -24,7 +24,7 @@ import java.util.List; import li.strolch.model.StrolchElement; import li.strolch.model.visitor.StrolchElementVisitor; import li.strolch.persistence.api.StrolchDao; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQueryVisitor.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQueryVisitor.java index ee952964c..bc8de2ab7 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQueryVisitor.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryQueryVisitor.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.query.AndSelection; import li.strolch.model.query.BooleanSelection; @@ -54,6 +53,7 @@ import li.strolch.model.query.ordering.StrolchQueryOrderingVisitor; import li.strolch.persistence.api.StrolchDao; import li.strolch.runtime.query.inmemory.ParameterBagSelector.NullParameterBagSelector; import li.strolch.runtime.query.inmemory.ParameterSelector.StringParameterSelector; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryVisitor.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryVisitor.java index 88ad97046..fd5989d52 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryVisitor.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryVisitor.java @@ -23,7 +23,7 @@ import li.strolch.model.query.ResourceQuery; import li.strolch.model.query.ResourceQueryVisitor; import li.strolch.model.query.StrolchTypeNavigation; import li.strolch.persistence.api.ResourceDao; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NameSelector.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NameSelector.java index 13b6c6d1f..862982d71 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NameSelector.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NameSelector.java @@ -15,8 +15,8 @@ */ package li.strolch.runtime.query.inmemory; -import ch.eitchnet.utils.StringMatchMode; import li.strolch.model.StrolchElement; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NotSelector.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NotSelector.java index 5cb86c337..ed4ac91d5 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NotSelector.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/NotSelector.java @@ -16,7 +16,7 @@ package li.strolch.runtime.query.inmemory; import li.strolch.model.StrolchElement; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/ParameterSelector.java b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/ParameterSelector.java index bb057e008..ef1459ee6 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/ParameterSelector.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/query/inmemory/ParameterSelector.java @@ -18,8 +18,6 @@ package li.strolch.runtime.query.inmemory; import java.util.Date; import java.util.List; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.collections.DateRange; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.ParameterBag; import li.strolch.model.parameter.BooleanParameter; @@ -31,6 +29,8 @@ import li.strolch.model.parameter.ListParameter; import li.strolch.model.parameter.LongParameter; import li.strolch.model.parameter.Parameter; import li.strolch.model.parameter.StringParameter; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/service/api/AbstractService.java b/li.strolch.agent/src/main/java/li/strolch/service/api/AbstractService.java index c1a162648..b91546e8d 100644 --- a/li.strolch.agent/src/main/java/li/strolch/service/api/AbstractService.java +++ b/li.strolch.agent/src/main/java/li/strolch/service/api/AbstractService.java @@ -20,19 +20,19 @@ import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.api.StrolchRealm; import li.strolch.exception.StrolchException; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg @@ -314,7 +314,7 @@ public abstract class AbstractService @@ -131,7 +131,7 @@ public abstract class Command implements Restrictable { } /** - * @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeName() + * @see li.strolch.privilege.model.Restrictable#getPrivilegeName() */ @Override public String getPrivilegeName() { @@ -139,7 +139,7 @@ public abstract class Command implements Restrictable { } /** - * @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeValue() + * @see li.strolch.privilege.model.Restrictable#getPrivilegeValue() */ @Override public Object getPrivilegeValue() { diff --git a/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java b/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java index 34a6c428e..a97275dcf 100644 --- a/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java @@ -17,17 +17,17 @@ package li.strolch.service.api; import java.text.MessageFormat; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.exception.StrolchAccessDeniedException; import li.strolch.exception.StrolchException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/main/java/li/strolch/service/api/Service.java b/li.strolch.agent/src/main/java/li/strolch/service/api/Service.java index 1bf0db9b9..ce07cf5c4 100644 --- a/li.strolch.agent/src/main/java/li/strolch/service/api/Service.java +++ b/li.strolch.agent/src/main/java/li/strolch/service/api/Service.java @@ -17,7 +17,7 @@ package li.strolch.service.api; import java.io.Serializable; -import ch.eitchnet.privilege.model.Restrictable; +import li.strolch.privilege.model.Restrictable; /** * Interface for Strolch service's. Service's are the main object in which business logic is implemented in a Strolch diff --git a/li.strolch.agent/src/main/java/li/strolch/service/api/ServiceHandler.java b/li.strolch.agent/src/main/java/li/strolch/service/api/ServiceHandler.java index 12899036f..3777bcfe7 100644 --- a/li.strolch.agent/src/main/java/li/strolch/service/api/ServiceHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/service/api/ServiceHandler.java @@ -15,7 +15,7 @@ */ package li.strolch.service.api; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; public interface ServiceHandler { diff --git a/li.strolch.agent/src/test/java/li/strolch/RuntimeMock.java b/li.strolch.agent/src/test/java/li/strolch/RuntimeMock.java index ef29aaa46..ca122ac65 100644 --- a/li.strolch.agent/src/test/java/li/strolch/RuntimeMock.java +++ b/li.strolch.agent/src/test/java/li/strolch/RuntimeMock.java @@ -26,8 +26,6 @@ import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.helper.FileHelper; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchBootstrapper; @@ -37,6 +35,8 @@ import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.service.api.ServiceHandler; import li.strolch.service.api.ServiceResult; import li.strolch.service.api.ServiceResultState; +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; /** * Basically you should use the RuntimeMock class in the testbase project, but to mitigate circular dependencies, in diff --git a/li.strolch.agent/src/test/java/li/strolch/agent/ComponentContainerTest.java b/li.strolch.agent/src/test/java/li/strolch/agent/ComponentContainerTest.java index a29ed8641..810838da8 100644 --- a/li.strolch.agent/src/test/java/li/strolch/agent/ComponentContainerTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/agent/ComponentContainerTest.java @@ -23,7 +23,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.RuntimeMock; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.OrderMap; @@ -35,6 +34,7 @@ import li.strolch.model.Resource; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.model.ResourceGeneratorHandlerTest; import li.strolch.runtime.configuration.model.ServiceHandlerTest; diff --git a/li.strolch.agent/src/test/java/li/strolch/policytest/PolicyHandlerTest.java b/li.strolch.agent/src/test/java/li/strolch/policytest/PolicyHandlerTest.java index a444a9952..a6fb49cd9 100644 --- a/li.strolch.agent/src/test/java/li/strolch/policytest/PolicyHandlerTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/policytest/PolicyHandlerTest.java @@ -19,7 +19,6 @@ import static org.junit.Assert.assertNotNull; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.RuntimeMock; import li.strolch.agent.ComponentContainerTest; import li.strolch.agent.api.ComponentContainer; @@ -27,6 +26,7 @@ import li.strolch.model.Resource; import li.strolch.model.policy.PolicyDef; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.policy.PolicyHandler; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; /** diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/BootstrapperTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/BootstrapperTest.java index 35c2adb63..27a2fb732 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/BootstrapperTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/BootstrapperTest.java @@ -6,10 +6,10 @@ import java.io.File; import org.junit.Test; -import ch.eitchnet.utils.helper.FileHelper; import li.strolch.RuntimeMock; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchBootstrapper; +import li.strolch.utils.helper.FileHelper; public class BootstrapperTest { diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ConfigurationParserTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ConfigurationParserTest.java index fdd60a343..8304f4e15 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ConfigurationParserTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ConfigurationParserTest.java @@ -23,10 +23,10 @@ import java.io.File; import org.junit.Test; -import ch.eitchnet.utils.helper.FileHelper; import li.strolch.RuntimeMock; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchBootstrapper; +import li.strolch.utils.helper.FileHelper; @SuppressWarnings("nls") public class ConfigurationParserTest { diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ControllerDependencyTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ControllerDependencyTest.java index ce62d9f98..b7d933463 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ControllerDependencyTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/configuration/ControllerDependencyTest.java @@ -30,13 +30,13 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import ch.eitchnet.utils.dbc.DBC.DbcException; import li.strolch.agent.api.ComponentState; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.impl.ComponentContainerImpl; import li.strolch.agent.impl.ComponentContainerStateHandler; import li.strolch.agent.impl.ComponentController; import li.strolch.agent.impl.ComponentDependencyAnalyzer; +import li.strolch.utils.dbc.DBC.DbcException; @SuppressWarnings("nls") public class ControllerDependencyTest { diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/enums/EnumHandlerTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/enums/EnumHandlerTest.java index 22aa63d94..fca2a2e31 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/enums/EnumHandlerTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/enums/EnumHandlerTest.java @@ -23,10 +23,10 @@ import java.util.Locale; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.RuntimeMock; import li.strolch.agent.ComponentContainerTest; import li.strolch.agent.api.ComponentContainer; +import li.strolch.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/AuditQueryTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/AuditQueryTest.java index 54d47e590..09366d006 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/AuditQueryTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/AuditQueryTest.java @@ -34,13 +34,12 @@ import li.strolch.model.audit.AuditQuery; import li.strolch.model.audit.AuditVisitor; import li.strolch.model.audit.NoStrategyAuditVisitor; import li.strolch.persistence.inmemory.InMemoryAuditDao; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.collections.DateRange; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.collections.DateRange; - /** * @author Robert von Burg */ diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/FindByLocatorTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/FindByLocatorTest.java index 88888ea64..45bc66957 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/FindByLocatorTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/FindByLocatorTest.java @@ -19,7 +19,6 @@ import static org.junit.Assert.assertNotNull; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.RuntimeMock; import li.strolch.agent.ComponentContainerTest; import li.strolch.agent.api.ComponentContainer; @@ -32,6 +31,7 @@ import li.strolch.model.parameter.FloatParameter; import li.strolch.model.parameter.StringParameter; import li.strolch.model.timedstate.IntegerTimedState; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; /** diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryQueryTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryQueryTest.java index 75c899b63..3dbca950a 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryQueryTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryQueryTest.java @@ -15,8 +15,6 @@ */ package li.strolch.runtime.query.inmemory; -import static ch.eitchnet.utils.StringMatchMode.ci; -import static ch.eitchnet.utils.StringMatchMode.es; import static li.strolch.model.query.ParameterSelection.booleanSelection; import static li.strolch.model.query.ParameterSelection.floatListSelection; import static li.strolch.model.query.ParameterSelection.floatSelection; @@ -24,6 +22,8 @@ import static li.strolch.model.query.ParameterSelection.integerListSelection; import static li.strolch.model.query.ParameterSelection.longListSelection; import static li.strolch.model.query.ParameterSelection.stringListSelection; import static li.strolch.model.query.ParameterSelection.stringSelection; +import static li.strolch.utils.StringMatchMode.ci; +import static li.strolch.utils.StringMatchMode.es; import static org.junit.Assert.assertEquals; import java.util.ArrayList; diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/QueryTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/QueryTest.java index 8a9c7f4f5..9b2994b1b 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/QueryTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/QueryTest.java @@ -26,8 +26,6 @@ import java.util.List; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.StringMatchMode; import li.strolch.RuntimeMock; import li.strolch.agent.ComponentContainerTest; import li.strolch.agent.api.ComponentContainer; @@ -40,7 +38,9 @@ import li.strolch.model.query.ParameterSelection; import li.strolch.model.query.ResourceQuery; import li.strolch.model.query.Selection; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeConfig.xml b/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeConfig.xml +++ b/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeRoles.xml b/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeRoles.xml +++ b/li.strolch.agent/src/test/resources/cachedtest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeConfig.xml b/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeConfig.xml +++ b/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeRoles.xml b/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeRoles.xml +++ b/li.strolch.agent/src/test/resources/emptytest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.agent/src/test/resources/log4j.xml b/li.strolch.agent/src/test/resources/log4j.xml index 0a2a73d06..7a0499275 100644 --- a/li.strolch.agent/src/test/resources/log4j.xml +++ b/li.strolch.agent/src/test/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeConfig.xml b/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeConfig.xml +++ b/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeRoles.xml b/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeRoles.xml +++ b/li.strolch.agent/src/test/resources/minimaltest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeConfig.xml b/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeConfig.xml +++ b/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeRoles.xml b/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeRoles.xml +++ b/li.strolch.agent/src/test/resources/realmtest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeConfig.xml b/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeConfig.xml +++ b/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeRoles.xml b/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeRoles.xml +++ b/li.strolch.agent/src/test/resources/transactionaltest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeConfig.xml b/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeConfig.xml +++ b/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeRoles.xml b/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeRoles.xml +++ b/li.strolch.agent/src/test/resources/transienttest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.bom/pom.xml b/li.strolch.bom/pom.xml index 183a07a2b..d3686ec1b 100644 --- a/li.strolch.bom/pom.xml +++ b/li.strolch.bom/pom.xml @@ -1,24 +1,19 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.bom pom li.strolch.bom The default set of dependencies to start working with strolch projects - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - @@ -52,7 +47,7 @@ li.strolch.rest ${project.version} - + li.strolch @@ -60,7 +55,7 @@ ${project.version} test - + diff --git a/li.strolch.dev/createBundle.sh b/li.strolch.dev/createBundle.sh index f5925067c..dfd7476e5 100755 --- a/li.strolch.dev/createBundle.sh +++ b/li.strolch.dev/createBundle.sh @@ -1,7 +1,7 @@ #!/bin/bash projectName=strolch_bundle -projectVersion=1.1.0-SNAPSHOT +projectVersion=1.2.0-SNAPSHOT bundle_name="${projectName}-${projectVersion}" DIST_STROLCH="/var/www/eitch/strolch.li/dist/snapshot" DEPLOY_SERVER="hosting.eitchnet.ch" diff --git a/li.strolch.dev/pom.xml b/li.strolch.dev/pom.xml index f1b9b0027..8a21f5d51 100644 --- a/li.strolch.dev/pom.xml +++ b/li.strolch.dev/pom.xml @@ -1,12 +1,13 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.dev @@ -14,10 +15,4 @@ li.strolch.dev Project used to develop strolch modules. Contains scripts for bootstrapping development, etc. - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - diff --git a/li.strolch.dev/projects_all.lst b/li.strolch.dev/projects_all.lst index 0cac22be3..049c79444 100644 --- a/li.strolch.dev/projects_all.lst +++ b/li.strolch.dev/projects_all.lst @@ -1,9 +1,7 @@ -ch.eitchnet.parent:develop -ch.eitchnet.privilege:develop -ch.eitchnet.utils:develop -ch.eitchnet.xmlpers:develop +li.strolch.utils:develop +li.strolch.privilege:develop +li.strolch.xmlpers:develop li.strolch.dev:develop -li.strolch.parent:develop li.strolch.bom:develop li.strolch.model:develop li.strolch.testbase:develop diff --git a/li.strolch.model/pom.xml b/li.strolch.model/pom.xml index e842bd7a0..b457bfa66 100644 --- a/li.strolch.model/pom.xml +++ b/li.strolch.model/pom.xml @@ -1,32 +1,20 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.model jar li.strolch.model - https://github.com/eitchnet/li.strolch.model - 2012 - - Github Issues - https://github.com/eitchnet/li.strolch.model/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - @@ -35,12 +23,12 @@ - ch.eitchnet - ch.eitchnet.utils + li.strolch + li.strolch.utils - ch.eitchnet - ch.eitchnet.privilege + li.strolch + li.strolch.privilege diff --git a/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java b/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java index 6f882c4c0..927d63aae 100644 --- a/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java +++ b/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java @@ -15,8 +15,8 @@ */ package li.strolch.exception; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.Restrictable; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.Restrictable; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/AbstractStrolchElement.java b/li.strolch.model/src/main/java/li/strolch/model/AbstractStrolchElement.java index 78da13090..7d7a149ca 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/AbstractStrolchElement.java +++ b/li.strolch.model/src/main/java/li/strolch/model/AbstractStrolchElement.java @@ -19,7 +19,7 @@ import java.text.MessageFormat; import li.strolch.exception.StrolchException; import li.strolch.model.Locator.LocatorBuilder; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/GroupedParameterizedElement.java b/li.strolch.model/src/main/java/li/strolch/model/GroupedParameterizedElement.java index f6dba5214..4b88df156 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/GroupedParameterizedElement.java +++ b/li.strolch.model/src/main/java/li/strolch/model/GroupedParameterizedElement.java @@ -22,10 +22,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.exception.StrolchException; import li.strolch.exception.StrolchModelException; import li.strolch.model.parameter.Parameter; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/Locator.java b/li.strolch.model/src/main/java/li/strolch/model/Locator.java index a1447d61f..89d0dada4 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/Locator.java +++ b/li.strolch.model/src/main/java/li/strolch/model/Locator.java @@ -22,7 +22,7 @@ import java.util.Iterator; import java.util.List; import li.strolch.exception.StrolchException; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** *

diff --git a/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java b/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java index 432eddae8..765c3b6b7 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java +++ b/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java @@ -23,8 +23,6 @@ import java.util.List; import java.util.Random; import java.util.Set; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.model.activity.Action; import li.strolch.model.activity.Activity; import li.strolch.model.audit.AccessType; @@ -55,6 +53,8 @@ import li.strolch.model.timevalue.impl.FloatValue; import li.strolch.model.timevalue.impl.IntegerValue; import li.strolch.model.timevalue.impl.StringSetValue; import li.strolch.model.timevalue.impl.ValueChange; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * Class which can be used to generate objects which implement {@link StrolchElement}. These generated classes can then diff --git a/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java b/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java index 30c21f1fa..66a7d7f24 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java +++ b/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java @@ -15,7 +15,7 @@ */ package li.strolch.model; -import static ch.eitchnet.utils.helper.StringHelper.NULL; +import static li.strolch.utils.helper.StringHelper.NULL; import java.util.Date; @@ -26,8 +26,8 @@ import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import li.strolch.model.xml.Iso8601DateAdapter; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/Order.java b/li.strolch.model/src/main/java/li/strolch/model/Order.java index d8fccb53c..07fddcb6e 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/Order.java +++ b/li.strolch.model/src/main/java/li/strolch/model/Order.java @@ -17,11 +17,11 @@ package li.strolch.model; import java.util.Date; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.exception.StrolchPolicyException; import li.strolch.model.Locator.LocatorBuilder; import li.strolch.model.policy.PolicyDefs; import li.strolch.model.visitor.StrolchRootElementVisitor; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * The Order is an object used in the EDF to transfer data from one range to another. Orders are not to be thought of as diff --git a/li.strolch.model/src/main/java/li/strolch/model/ParameterizedElement.java b/li.strolch.model/src/main/java/li/strolch/model/ParameterizedElement.java index edcef9f18..3a3eb7d77 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/ParameterizedElement.java +++ b/li.strolch.model/src/main/java/li/strolch/model/ParameterizedElement.java @@ -24,10 +24,10 @@ import java.util.List; import java.util.Map; import java.util.Set; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.exception.StrolchException; import li.strolch.model.Locator.LocatorBuilder; import li.strolch.model.parameter.Parameter; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java b/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java index f02aabce4..d4118c4eb 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java +++ b/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java @@ -21,7 +21,6 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.exception.StrolchException; import li.strolch.exception.StrolchPolicyException; import li.strolch.model.GroupedParameterizedElement; @@ -34,6 +33,7 @@ import li.strolch.model.StrolchRootElement; import li.strolch.model.Tags; import li.strolch.model.policy.PolicyDefs; import li.strolch.model.visitor.StrolchRootElementVisitor; +import li.strolch.utils.dbc.DBC; /** * Parameterized object grouping a collection of {@link Activity} and {@link Action} objects defining the process to be diff --git a/li.strolch.model/src/main/java/li/strolch/model/audit/ActionSelection.java b/li.strolch.model/src/main/java/li/strolch/model/audit/ActionSelection.java index 60c6ed1ca..68abb4fd7 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/audit/ActionSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/audit/ActionSelection.java @@ -16,7 +16,7 @@ package li.strolch.model.audit; import li.strolch.model.query.StringSelection; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/audit/AuditFromDomReader.java b/li.strolch.model/src/main/java/li/strolch/model/audit/AuditFromDomReader.java index 44e886307..7e8c9afca 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/audit/AuditFromDomReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/audit/AuditFromDomReader.java @@ -18,14 +18,13 @@ package li.strolch.model.audit; import java.text.MessageFormat; import li.strolch.model.Tags; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.iso8601.ISO8601FormatFactory; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/main/java/li/strolch/model/audit/AuditQuery.java b/li.strolch.model/src/main/java/li/strolch/model/audit/AuditQuery.java index cf547e48b..0b08a1ddb 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/audit/AuditQuery.java +++ b/li.strolch.model/src/main/java/li/strolch/model/audit/AuditQuery.java @@ -19,8 +19,8 @@ import java.util.ArrayList; import java.util.List; import li.strolch.model.query.StrolchQuery; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.dbc.DBC; /** * @@ -103,7 +103,7 @@ public class AuditQuery implements StrolchQuery { } /** - * @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeName() + * @see li.strolch.privilege.model.Restrictable#getPrivilegeName() */ @Override public String getPrivilegeName() { @@ -111,7 +111,7 @@ public class AuditQuery implements StrolchQuery { } /** - * @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeValue() + * @see li.strolch.privilege.model.Restrictable#getPrivilegeValue() */ @Override public Object getPrivilegeValue() { diff --git a/li.strolch.model/src/main/java/li/strolch/model/audit/AuditToDomVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/audit/AuditToDomVisitor.java index 91f43753e..4ef48fef8 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/audit/AuditToDomVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/audit/AuditToDomVisitor.java @@ -18,13 +18,12 @@ package li.strolch.model.audit; import javax.xml.parsers.DocumentBuilder; import li.strolch.model.Tags; +import li.strolch.utils.helper.DomUtil; +import li.strolch.utils.iso8601.ISO8601FormatFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import ch.eitchnet.utils.helper.DomUtil; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/main/java/li/strolch/model/audit/ElementSelection.java b/li.strolch.model/src/main/java/li/strolch/model/audit/ElementSelection.java index b24014aaa..19023114a 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/audit/ElementSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/audit/ElementSelection.java @@ -16,7 +16,7 @@ package li.strolch.model.audit; import li.strolch.model.query.StringSelection; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/audit/IdentitySelection.java b/li.strolch.model/src/main/java/li/strolch/model/audit/IdentitySelection.java index 0c6e88689..66c0656e7 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/audit/IdentitySelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/audit/IdentitySelection.java @@ -16,7 +16,7 @@ package li.strolch.model.audit; import li.strolch.model.query.StringSelection; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/json/StrolchElementToJsonVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/json/StrolchElementToJsonVisitor.java index d28367ec5..fa2519bee 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/json/StrolchElementToJsonVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/json/StrolchElementToJsonVisitor.java @@ -7,7 +7,6 @@ import java.util.SortedSet; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.model.AbstractStrolchElement; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Order; @@ -23,6 +22,7 @@ import li.strolch.model.policy.PolicyDefs; import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.ITimeValue; import li.strolch.model.timevalue.IValue; +import li.strolch.utils.iso8601.ISO8601FormatFactory; public class StrolchElementToJsonVisitor { diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/AbstractParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/AbstractParameter.java index 72f07740e..8a6f68025 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/AbstractParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/AbstractParameter.java @@ -27,7 +27,7 @@ import li.strolch.model.Locator.LocatorBuilder; import li.strolch.model.ParameterizedElement; import li.strolch.model.StrolchRootElement; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/BooleanParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/BooleanParameter.java index 78b8d406c..2015a9821 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/BooleanParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/BooleanParameter.java @@ -17,8 +17,8 @@ package li.strolch.model.parameter; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/DateParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/DateParameter.java index 1106674e6..f99048aa6 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/DateParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/DateParameter.java @@ -19,8 +19,8 @@ import java.util.Date; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java index 5ff87199d..3f60d7a60 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java @@ -17,8 +17,8 @@ package li.strolch.model.parameter; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatListParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatListParameter.java index 3248224aa..cb641a5e6 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatListParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatListParameter.java @@ -22,8 +22,8 @@ import java.util.List; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatParameter.java index 74a86ddeb..b4efa6b25 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/FloatParameter.java @@ -15,9 +15,9 @@ */ package li.strolch.model.parameter; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerListParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerListParameter.java index 32d2b9010..da510ed81 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerListParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerListParameter.java @@ -22,8 +22,8 @@ import java.util.List; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerParameter.java index ee5321e4a..b1e17ca62 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/IntegerParameter.java @@ -15,9 +15,9 @@ */ package li.strolch.model.parameter; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/LongListParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/LongListParameter.java index b61da8c34..b3f55ad92 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/LongListParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/LongListParameter.java @@ -22,8 +22,8 @@ import java.util.List; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/LongParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/LongParameter.java index 08491e178..f6d876155 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/LongParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/LongParameter.java @@ -15,9 +15,9 @@ */ package li.strolch.model.parameter; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/StringListParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/StringListParameter.java index 53e3180bd..8ef1685af 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/StringListParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/StringListParameter.java @@ -22,8 +22,8 @@ import java.util.List; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/StringParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/StringParameter.java index a10522e81..516ed4597 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/StringParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/StringParameter.java @@ -17,7 +17,7 @@ package li.strolch.model.parameter; import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.ParameterVisitor; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/policy/PolicyDefs.java b/li.strolch.model/src/main/java/li/strolch/model/policy/PolicyDefs.java index 2576b4a0c..b3e6e372a 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/policy/PolicyDefs.java +++ b/li.strolch.model/src/main/java/li/strolch/model/policy/PolicyDefs.java @@ -19,10 +19,10 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.exception.StrolchPolicyException; import li.strolch.model.StrolchElement; import li.strolch.model.StrolchRootElement; +import li.strolch.utils.dbc.DBC; /** * The {@link PolicyDefs} contains the policy configuration of any {@link StrolchRootElement} which requires policies diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/ActivityQuery.java b/li.strolch.model/src/main/java/li/strolch/model/query/ActivityQuery.java index bd19935d7..3da10d7b9 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/ActivityQuery.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/ActivityQuery.java @@ -15,12 +15,12 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.ActivityVisitor; import li.strolch.model.activity.Action; import li.strolch.model.activity.Activity; import li.strolch.model.query.ordering.StrolchQueryOrdering; import li.strolch.model.visitor.NoStrategyActivityVisitor; +import li.strolch.utils.dbc.DBC; /** *

diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/DateSelection.java b/li.strolch.model/src/main/java/li/strolch/model/query/DateSelection.java index ea3ef2645..8531e9522 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/DateSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/DateSelection.java @@ -17,7 +17,7 @@ package li.strolch.model.query; import java.util.Date; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/IdSelection.java b/li.strolch.model/src/main/java/li/strolch/model/query/IdSelection.java index f4adc9cad..c65beaf43 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/IdSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/IdSelection.java @@ -19,7 +19,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/NameSelection.java b/li.strolch.model/src/main/java/li/strolch/model/query/NameSelection.java index 9b618563d..41ce77a0e 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/NameSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/NameSelection.java @@ -15,7 +15,7 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/OrderQuery.java b/li.strolch.model/src/main/java/li/strolch/model/query/OrderQuery.java index c7400c971..1bece9361 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/OrderQuery.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/OrderQuery.java @@ -15,12 +15,12 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.Order; import li.strolch.model.OrderVisitor; import li.strolch.model.parameter.Parameter; import li.strolch.model.query.ordering.StrolchQueryOrdering; import li.strolch.model.visitor.NoStrategyOrderVisitor; +import li.strolch.utils.dbc.DBC; /** *

diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/ParameterSelection.java b/li.strolch.model/src/main/java/li/strolch/model/query/ParameterSelection.java index 84fec6049..4c1fc64a3 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/ParameterSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/ParameterSelection.java @@ -18,10 +18,10 @@ package li.strolch.model.query; import java.util.Date; import java.util.List; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/ResourceQuery.java b/li.strolch.model/src/main/java/li/strolch/model/query/ResourceQuery.java index c57a9d609..a42e3fd05 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/ResourceQuery.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/ResourceQuery.java @@ -15,12 +15,12 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.Resource; import li.strolch.model.ResourceVisitor; import li.strolch.model.parameter.Parameter; import li.strolch.model.query.ordering.StrolchQueryOrdering; import li.strolch.model.visitor.NoStrategyResourceVisitor; +import li.strolch.utils.dbc.DBC; /** *

diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/StringSelection.java b/li.strolch.model/src/main/java/li/strolch/model/query/StringSelection.java index f5fa5d39a..8fa88be1b 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/StringSelection.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/StringSelection.java @@ -15,7 +15,7 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/StrolchElementQuery.java b/li.strolch.model/src/main/java/li/strolch/model/query/StrolchElementQuery.java index 0537d4b93..a86f8cee3 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/StrolchElementQuery.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/StrolchElementQuery.java @@ -15,7 +15,7 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg @@ -98,7 +98,7 @@ public abstract class StrolchElementQuery implements Str } /** - * @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeName() + * @see li.strolch.privilege.model.Restrictable#getPrivilegeName() */ @Override public String getPrivilegeName() { @@ -106,7 +106,7 @@ public abstract class StrolchElementQuery implements Str } /** - * @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeValue() + * @see li.strolch.privilege.model.Restrictable#getPrivilegeValue() */ @Override public Object getPrivilegeValue() { diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/StrolchQuery.java b/li.strolch.model/src/main/java/li/strolch/model/query/StrolchQuery.java index 018e3b9e4..de1d56cf5 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/StrolchQuery.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/StrolchQuery.java @@ -15,7 +15,7 @@ */ package li.strolch.model.query; -import ch.eitchnet.privilege.model.Restrictable; +import li.strolch.privilege.model.Restrictable; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/query/StrolchTypeNavigation.java b/li.strolch.model/src/main/java/li/strolch/model/query/StrolchTypeNavigation.java index 026209047..66a7d8340 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/query/StrolchTypeNavigation.java +++ b/li.strolch.model/src/main/java/li/strolch/model/query/StrolchTypeNavigation.java @@ -15,7 +15,7 @@ */ package li.strolch.model.query; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/timedstate/AbstractStrolchTimedState.java b/li.strolch.model/src/main/java/li/strolch/model/timedstate/AbstractStrolchTimedState.java index ca27e5365..4f65d5fc6 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/timedstate/AbstractStrolchTimedState.java +++ b/li.strolch.model/src/main/java/li/strolch/model/timedstate/AbstractStrolchTimedState.java @@ -29,7 +29,7 @@ import li.strolch.model.timevalue.ITimeVariable; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.IValueChange; import li.strolch.model.visitor.TimedStateVisitor; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * Wrapper for a {@link IntegerTimedState} diff --git a/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/AString.java b/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/AString.java index 3f8e34b6a..27f988192 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/AString.java +++ b/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/AString.java @@ -17,7 +17,7 @@ package li.strolch.model.timevalue.impl; import java.io.Serializable; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * Wrapper for java.util.String object defining a inverse to support algebraic operations. diff --git a/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/StringSetValue.java b/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/StringSetValue.java index da42f9b7e..9d3057c92 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/StringSetValue.java +++ b/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/StringSetValue.java @@ -21,12 +21,12 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.exception.StrolchException; import li.strolch.model.StrolchValueType; import li.strolch.model.timevalue.ITimeValue; import li.strolch.model.timevalue.IValue; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * {@link IValue} implementation to work with String valued {@link ITimeValue} objects. Since a java.util.String object diff --git a/li.strolch.model/src/main/java/li/strolch/model/visitor/StrolchElementDeepEqualsVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/visitor/StrolchElementDeepEqualsVisitor.java index a9812e9bb..eea7cdfcd 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/visitor/StrolchElementDeepEqualsVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/visitor/StrolchElementDeepEqualsVisitor.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.Map.Entry; import java.util.Set; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Locator; import li.strolch.model.Order; @@ -36,6 +35,7 @@ import li.strolch.model.policy.PolicyDef; import li.strolch.model.policy.PolicyDefs; import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.ITimeVariable; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/ActivityToDomVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/ActivityToDomVisitor.java index 293945e2a..b4e40a211 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/ActivityToDomVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/ActivityToDomVisitor.java @@ -20,10 +20,10 @@ import javax.xml.parsers.DocumentBuilder; import org.w3c.dom.Document; import org.w3c.dom.Element; -import ch.eitchnet.utils.helper.DomUtil; import li.strolch.model.ActivityVisitor; import li.strolch.model.activity.Action; import li.strolch.model.activity.Activity; +import li.strolch.utils.helper.DomUtil; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/Iso8601DateAdapter.java b/li.strolch.model/src/main/java/li/strolch/model/xml/Iso8601DateAdapter.java index dbfb38c22..852b319c0 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/Iso8601DateAdapter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/Iso8601DateAdapter.java @@ -24,7 +24,7 @@ import javax.xml.bind.annotation.adapters.XmlAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; public class Iso8601DateAdapter extends XmlAdapter { diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToDomVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToDomVisitor.java index 07dc7829b..643168e60 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToDomVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToDomVisitor.java @@ -19,12 +19,11 @@ import javax.xml.parsers.DocumentBuilder; import li.strolch.model.Order; import li.strolch.model.OrderVisitor; +import li.strolch.utils.helper.DomUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; -import ch.eitchnet.utils.helper.DomUtil; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToXmlStringVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToXmlStringVisitor.java index bd4c5d1f7..cd9c0fbed 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToXmlStringVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/OrderToXmlStringVisitor.java @@ -25,7 +25,7 @@ import javax.xml.stream.XMLStreamWriter; import li.strolch.model.Order; import li.strolch.model.OrderVisitor; import li.strolch.model.StrolchModelConstants; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToDomVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToDomVisitor.java index e783bcfc1..4971650d9 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToDomVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToDomVisitor.java @@ -19,12 +19,11 @@ import javax.xml.parsers.DocumentBuilder; import li.strolch.model.Resource; import li.strolch.model.ResourceVisitor; +import li.strolch.utils.helper.DomUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; -import ch.eitchnet.utils.helper.DomUtil; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToXmlStringVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToXmlStringVisitor.java index 0b520e3c8..70ed72726 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToXmlStringVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/ResourceToXmlStringVisitor.java @@ -20,11 +20,11 @@ import java.io.StringWriter; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; -import ch.eitchnet.utils.dbc.DBC; import javanet.staxutils.IndentingXMLStreamWriter; import li.strolch.model.Resource; import li.strolch.model.ResourceVisitor; import li.strolch.model.StrolchModelConstants; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementFromDomVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementFromDomVisitor.java index 4811dfad3..195ff2adc 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementFromDomVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementFromDomVisitor.java @@ -22,9 +22,6 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.exception.StrolchException; import li.strolch.model.AbstractStrolchElement; import li.strolch.model.GroupedParameterizedElement; @@ -43,6 +40,9 @@ import li.strolch.model.policy.PolicyDefs; import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.impl.ValueChange; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToDomVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToDomVisitor.java index bf0d5b5f6..d930e5cd8 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToDomVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToDomVisitor.java @@ -22,7 +22,6 @@ import java.util.SortedSet; import org.w3c.dom.Document; import org.w3c.dom.Element; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.model.AbstractStrolchElement; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Order; @@ -41,6 +40,7 @@ import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.ITimeValue; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.IValueChange; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxVisitor.java index afdc5d313..215aec401 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxVisitor.java @@ -28,7 +28,6 @@ import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Order; import li.strolch.model.ParameterBag; @@ -45,6 +44,7 @@ import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.ITimeValue; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.IValueChange; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxWriterVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxWriterVisitor.java index 3dfd042f7..4b96a443d 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxWriterVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/StrolchElementToSaxWriterVisitor.java @@ -30,7 +30,6 @@ import java.util.TreeSet; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Order; import li.strolch.model.ParameterBag; @@ -49,6 +48,7 @@ import li.strolch.model.timevalue.ITimeValue; import li.strolch.model.timevalue.ITimeVariable; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.IValueChange; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java index 1c2d9be32..4dc507655 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java @@ -24,12 +24,11 @@ import javax.xml.parsers.SAXParserFactory; import li.strolch.exception.StrolchException; import li.strolch.model.Tags; +import li.strolch.utils.helper.StringHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; -import ch.eitchnet.utils.helper.StringHelper; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java index e89feb89d..5ed039af3 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java @@ -26,8 +26,6 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.exception.StrolchException; import li.strolch.exception.StrolchPolicyException; import li.strolch.model.GroupedParameterizedElement; @@ -46,6 +44,8 @@ import li.strolch.model.policy.PolicyDefs; import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.impl.ValueChange; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java index 6c7089b03..f1febea36 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java @@ -26,12 +26,11 @@ import javax.xml.parsers.SAXParserFactory; import li.strolch.exception.StrolchException; import li.strolch.model.Tags; +import li.strolch.utils.helper.StringHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; -import ch.eitchnet.utils.helper.StringHelper; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/test/java/li/strolch/model/XmlModelDefaultHandlerTest.java b/li.strolch.model/src/test/java/li/strolch/model/XmlModelDefaultHandlerTest.java index 2d698523f..91c996474 100644 --- a/li.strolch.model/src/test/java/li/strolch/model/XmlModelDefaultHandlerTest.java +++ b/li.strolch.model/src/test/java/li/strolch/model/XmlModelDefaultHandlerTest.java @@ -24,13 +24,12 @@ import java.util.Map; import li.strolch.model.activity.Activity; import li.strolch.model.xml.StrolchElementListener; import li.strolch.model.xml.XmlModelSaxFileReader; +import li.strolch.utils.helper.StringHelper; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.helper.StringHelper; - /** * @author Robert von Burg */ diff --git a/li.strolch.model/src/test/resources/log4j.xml b/li.strolch.model/src/test/resources/log4j.xml index 0a2a73d06..7a0499275 100644 --- a/li.strolch.model/src/test/resources/log4j.xml +++ b/li.strolch.model/src/test/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.parent/.gitignore b/li.strolch.parent/.gitignore deleted file mode 100644 index 6efaec8b2..000000000 --- a/li.strolch.parent/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target/ -.project -.settings diff --git a/li.strolch.parent/README.md b/li.strolch.parent/README.md deleted file mode 100644 index f5ff4305e..000000000 --- a/li.strolch.parent/README.md +++ /dev/null @@ -1,6 +0,0 @@ -li.strolch.parent -================= - -[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=li.strolch.parent)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.parent/) - -Parent for all li.strolch projects for easier project maintenance diff --git a/li.strolch.parent/pom.xml b/li.strolch.parent/pom.xml deleted file mode 100644 index 3d70b08fa..000000000 --- a/li.strolch.parent/pom.xml +++ /dev/null @@ -1,428 +0,0 @@ - - - 4.0.0 - - - li.strolch - li.strolch - 1.1.0-SNAPSHOT - ../pom.xml - - - li.strolch.parent - pom - li.strolch.parent - Parent for all li.strolch projects for easier project maintenance - 2013 - - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - - - - Apache License 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - - - - - eitchnet.ch - http://www.strolch.li - - - - - eitch - Robert von Burg - eitch@eitchnet.ch - http://www.eitchnet.ch - eitchnet.ch - http://www.eitchnet.ch - - architect - developer - - +1 - - - - - - - li.strolch - li.strolch.model - ${project.version} - - - li.strolch - li.strolch.agent - ${project.version} - - - li.strolch - li.strolch.service - ${project.version} - - - li.strolch - li.strolch.persistence.xml - ${project.version} - - - li.strolch - li.strolch.persistence.postgresql - ${project.version} - - - li.strolch - li.strolch.rest - ${project.version} - - - - - li.strolch - li.strolch.testbase - ${project.version} - test - - - - - ch.eitchnet - ch.eitchnet.utils - ${eitchnet.utils.version} - - - ch.eitchnet - ch.eitchnet.xmlpers - ${eitchnet.xmlpers.version} - - - ch.eitchnet - ch.eitchnet.privilege - ${eitchnet.privilege.version} - - - - - org.slf4j - slf4j-api - 1.7.2 - - - commons-cli - commons-cli - 1.2 - - - com.github.petitparser.java-petitparser - petitparser-core - 2.0.2 - - - - - com.google.code.gson - gson - 2.3.1 - - - - - javax.mail - mail - 1.5.0-b01 - - - - - javax.servlet - javax.servlet-api - 3.0.1 - provided - - - - - junit - junit - 4.11 - test - - - org.hamcrest - hamcrest-core - 1.3 - test - - - org.hamcrest - hamcrest-library - 1.3 - test - - - org.slf4j - slf4j-log4j12 - 1.7.2 - test - - - - - - - - - ch.eitchnet - ch.eitchnet.utils - - - org.slf4j - slf4j-api - - - - - junit - junit - test - - - org.hamcrest - hamcrest-core - test - - - org.hamcrest - hamcrest-library - test - - - org.slf4j - slf4j-log4j12 - test - - - - - - - src/main/resources - true - - - - - - - org.codehaus.mojo - versions-maven-plugin - 2.2 - - - org.apache.maven.plugins - maven-scm-plugin - 1.9.4 - - ${project.artifactId}-${project.version} - - - - - org.codehaus.mojo - buildnumber-maven-plugin - 1.3 - - - validate - - create - - - - - false - false - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - true - true - -Xlint:all - - - - - org.apache.maven.plugins - maven-site-plugin - 3.4 - - UTF-8 - - - - org.apache.maven.plugins - maven-eclipse-plugin - 2.10 - - true - true - - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - attach-sources - package - - jar-no-fork - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - true - true - - - - - - - - - - - - org.apache.maven.plugins - maven-war-plugin - 2.6 - - false - ${warFinalName} - - - - - org.apache.tomcat.maven - tomcat7-maven-plugin - 2.2 - - ${tomcat7Url} - ${tomcat7ServerId} - /${warFinalName} - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - - attach-javadocs - deploy - - jar - - - - - -Xdoclint:none - - - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - - deploy - deploy - - deploy - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - 2.10 - - - copy-dependencies - package - - copy-dependencies - - - ${project.build.directory}/lib - false - false - true - false - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 2.5.5 - - - - true - - - - - - - - - - - - - - - - - - - - - - - diff --git a/li.strolch.performancetest/pom.xml b/li.strolch.performancetest/pom.xml index 1161604ec..27249a2fa 100644 --- a/li.strolch.performancetest/pom.xml +++ b/li.strolch.performancetest/pom.xml @@ -1,32 +1,20 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.performancetest - li.strolch.performancetest Strolch project for running performance tests - 2015 - - - - li.strolch - li.strolch.bom - pom - ${project.version} - - - - li.strolch diff --git a/li.strolch.performancetest/src/main/resources/log4j.xml b/li.strolch.performancetest/src/main/resources/log4j.xml index db9a7424c..983562023 100644 --- a/li.strolch.performancetest/src/main/resources/log4j.xml +++ b/li.strolch.performancetest/src/main/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeConfig.xml b/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeConfig.xml index 706602750..aaf42b2c6 100644 --- a/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeConfig.xml +++ b/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,7 +24,7 @@ - + \ No newline at end of file diff --git a/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeRoles.xml b/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeRoles.xml +++ b/li.strolch.performancetest/src/runtime_postgresql/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.performancetest/src/runtime_xml/config/PrivilegeConfig.xml b/li.strolch.performancetest/src/runtime_xml/config/PrivilegeConfig.xml index 706602750..aaf42b2c6 100644 --- a/li.strolch.performancetest/src/runtime_xml/config/PrivilegeConfig.xml +++ b/li.strolch.performancetest/src/runtime_xml/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,7 +24,7 @@ - + \ No newline at end of file diff --git a/li.strolch.performancetest/src/runtime_xml/config/PrivilegeRoles.xml b/li.strolch.performancetest/src/runtime_xml/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.performancetest/src/runtime_xml/config/PrivilegeRoles.xml +++ b/li.strolch.performancetest/src/runtime_xml/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformancePostgreSqlTest.java b/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformancePostgreSqlTest.java index dfa33bea3..cf202f94e 100644 --- a/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformancePostgreSqlTest.java +++ b/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformancePostgreSqlTest.java @@ -25,11 +25,11 @@ import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.db.DbSchemaVersionCheck; -import ch.eitchnet.utils.Version; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.db.DbSchemaVersionCheck; import li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.Version; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTest.java b/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTest.java index 5b2d774f2..7f9c1bfa5 100644 --- a/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTest.java +++ b/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTest.java @@ -2,7 +2,7 @@ package li.strolch.performance; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; import li.strolch.service.api.ServiceHandler; import li.strolch.testbase.runtime.RuntimeMock; diff --git a/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTestService.java b/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTestService.java index df0dc86e1..3126c48aa 100644 --- a/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTestService.java +++ b/li.strolch.performancetest/src/test/java/li/strolch/performance/PerformanceTestService.java @@ -17,7 +17,6 @@ package li.strolch.performance; import java.util.concurrent.TimeUnit; -import ch.eitchnet.utils.helper.SystemHelper; import li.strolch.agent.api.StrolchAgent; import li.strolch.command.AddResourceCommand; import li.strolch.command.RemoveResourceCommand; @@ -26,6 +25,7 @@ import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceResult; +import li.strolch.utils.helper.SystemHelper; public class PerformanceTestService extends AbstractService { diff --git a/li.strolch.persistence.postgresql/pom.xml b/li.strolch.persistence.postgresql/pom.xml index d00eed9b9..2707aeda0 100644 --- a/li.strolch.persistence.postgresql/pom.xml +++ b/li.strolch.persistence.postgresql/pom.xml @@ -1,34 +1,20 @@ - + li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml 4.0.0 li.strolch.persistence.postgresql - li.strolch.persistence.postgresql PostgreSQL Persistence Implementation for Strolch - - https://github.com/eitchnet/li.strolch.persistence.postgresql - 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.persistence.postgresql/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - @@ -43,13 +29,10 @@ com.zaxxer HikariCP - 2.3.6 - compile org.postgresql postgresql - 9.4.1208.jre7 diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java index 93094c74a..ae51ea24f 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java @@ -31,8 +31,8 @@ import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.StrolchPersistenceException; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java index f3be5d0df..a69386e29 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java @@ -27,7 +27,7 @@ import li.strolch.model.audit.AuditQueryVisitor; import li.strolch.model.audit.ElementSelection; import li.strolch.model.audit.IdentitySelection; import li.strolch.model.query.StringSelection; -import ch.eitchnet.utils.StringMatchMode; +import li.strolch.utils.StringMatchMode; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbConnectionBuilder.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbConnectionBuilder.java index 4ff8232f7..095b6ae84 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbConnectionBuilder.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbConnectionBuilder.java @@ -27,10 +27,10 @@ import javax.sql.DataSource; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.agent.api.ComponentContainer; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.DbConnectionBuilder; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbInitializer.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbInitializer.java index b472d4261..5a7903850 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbInitializer.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlDbInitializer.java @@ -3,9 +3,9 @@ */ package li.strolch.persistence.postgresql; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_SCHEMA_CREATION; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_SCHEMA_DROP; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_SCHEMA_MIGRATION; +import static li.strolch.db.DbConstants.PROP_ALLOW_SCHEMA_CREATION; +import static li.strolch.db.DbConstants.PROP_ALLOW_SCHEMA_DROP; +import static li.strolch.db.DbConstants.PROP_ALLOW_SCHEMA_MIGRATION; import java.util.Map; import java.util.Map.Entry; @@ -14,16 +14,16 @@ import javax.sql.DataSource; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchRealm; +import li.strolch.db.DbConnectionCheck; +import li.strolch.db.DbException; +import li.strolch.db.DbMigrationState; +import li.strolch.db.DbSchemaVersionCheck; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.configuration.StrolchConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; -import ch.eitchnet.db.DbConnectionCheck; -import ch.eitchnet.db.DbException; -import ch.eitchnet.db.DbMigrationState; -import ch.eitchnet.db.DbSchemaVersionCheck; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; public class PostgreSqlDbInitializer extends PostgreSqlInitializer { diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java index b552d9e2d..36916fbea 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java @@ -19,8 +19,8 @@ import java.sql.Date; import java.util.ArrayList; import java.util.List; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlInitializer.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlInitializer.java index 8b351e95f..745bfd157 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlInitializer.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlInitializer.java @@ -24,9 +24,12 @@ import java.text.MessageFormat; import li.strolch.agent.api.RealmHandler; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.impl.StoreToDaoElementListener; +import li.strolch.db.DbMigrationState; import li.strolch.model.ModelStatistics; import li.strolch.model.xml.XmlModelSaxFileReader; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.configuration.StrolchConfiguration; @@ -34,10 +37,6 @@ import li.strolch.runtime.configuration.StrolchConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.db.DbMigrationState; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.Certificate; - /** * @author Robert von Burg */ diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 2a6a044e2..35f24d814 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -15,11 +15,11 @@ */ package li.strolch.persistence.postgresql; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_DATA_INIT_ON_SCHEMA_CREATE; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_SCHEMA_CREATION; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_SCHEMA_DROP; -import static ch.eitchnet.db.DbConstants.PROP_ALLOW_SCHEMA_MIGRATION; import static li.strolch.agent.api.RealmHandler.SYSTEM_USER_DB_INITIALIZER; +import static li.strolch.db.DbConstants.PROP_ALLOW_DATA_INIT_ON_SCHEMA_CREATE; +import static li.strolch.db.DbConstants.PROP_ALLOW_SCHEMA_CREATION; +import static li.strolch.db.DbConstants.PROP_ALLOW_SCHEMA_DROP; +import static li.strolch.db.DbConstants.PROP_ALLOW_SCHEMA_MIGRATION; import java.sql.Connection; import java.text.MessageFormat; @@ -30,14 +30,13 @@ import javax.sql.DataSource; import org.postgresql.Driver; -import ch.eitchnet.db.DbMigrationState; -import ch.eitchnet.db.DbSchemaVersionCheck; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.RealmHandler; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.api.StrolchRealm; +import li.strolch.db.DbMigrationState; +import li.strolch.db.DbSchemaVersionCheck; import li.strolch.persistence.api.ActivityDao; import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.OrderDao; @@ -46,6 +45,7 @@ import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.postgresql.PostgreSqlDbConnectionBuilder.StrolchPostgreDataSource; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.DbConnectionBuilder; import li.strolch.runtime.configuration.StrolchConfiguration; diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java index fe6b876ec..df24584b1 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java @@ -23,10 +23,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.model.query.AndSelection; import li.strolch.model.query.IdSelection; import li.strolch.model.query.NameSelection; @@ -56,6 +52,10 @@ import li.strolch.model.query.ordering.OrderById; import li.strolch.model.query.ordering.OrderByName; import li.strolch.model.query.ordering.OrderByParameter; import li.strolch.model.query.ordering.StrolchQueryOrderingVisitor; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlSchemaInitializer.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlSchemaInitializer.java index 93e7e56f1..2022ad195 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlSchemaInitializer.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlSchemaInitializer.java @@ -19,9 +19,9 @@ import java.util.Map; import java.util.Map.Entry; import li.strolch.agent.api.StrolchAgent; -import ch.eitchnet.db.DbMigrationState; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.db.DbMigrationState; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 24c3d5b28..7b0519849 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -25,13 +25,12 @@ import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.TransactionResult; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; - public class PostgreSqlStrolchTransaction extends AbstractTransaction { private static final Logger logger = LoggerFactory.getLogger(PostgreSqlStrolchTransaction.class); diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java index 19a0932b6..4cb0e019d 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java @@ -43,9 +43,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.collections.DateRange; import li.strolch.agent.api.AuditTrail; import li.strolch.agent.api.StrolchRealm; import li.strolch.model.ModelGenerator; @@ -58,8 +55,11 @@ import li.strolch.model.audit.NoStrategyAuditVisitor; import li.strolch.persistence.api.AbstractTransaction; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.postgresql.PostgreSqlAuditQueryVisitor; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java index d8338283b..ece4d9b55 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java @@ -26,12 +26,12 @@ import org.postgresql.Driver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.db.DbSchemaVersionCheck; -import ch.eitchnet.utils.Version; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.db.DbSchemaVersionCheck; import li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler; import li.strolch.testbase.runtime.AbstractModelTest; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.Version; +import li.strolch.utils.helper.StringHelper; public class CachedDaoTest extends AbstractModelTest { diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/DbMigrationTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/DbMigrationTest.java index 3ad34b7fa..b772b6535 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/DbMigrationTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/DbMigrationTest.java @@ -25,16 +25,15 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.text.MessageFormat; +import li.strolch.db.DbException; +import li.strolch.db.DbSchemaVersionCheck; import li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler; import li.strolch.runtime.StrolchConstants; +import li.strolch.utils.Version; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.db.DbException; -import ch.eitchnet.db.DbSchemaVersionCheck; -import ch.eitchnet.utils.Version; - /** * @author Robert von Burg */ diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 11e1df28e..dec3ee3be 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -38,6 +38,7 @@ import li.strolch.model.StrolchRootElement; import li.strolch.model.Tags; import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.RuntimeMock; @@ -46,8 +47,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; - /** * @author Robert von Burg */ diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java index 8d2a6ee9f..4ce3cebbf 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java @@ -42,9 +42,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; import li.strolch.agent.api.StrolchRealm; @@ -67,8 +64,11 @@ import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.postgresql.PostgreSqlOrderQueryVisitor; import li.strolch.persistence.postgresql.PostgreSqlQueryVisitor; import li.strolch.persistence.postgresql.PostgreSqlResourceQueryVisitor; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java index 77b6ca41e..da8613545 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -26,12 +26,12 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.agent.api.StrolchRealm; import li.strolch.agent.impl.DataStoreMode; import li.strolch.model.ModelGenerator; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.AbstractModelTest; import li.strolch.testbase.runtime.RuntimeMock; diff --git a/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeConfig.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeRoles.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeRoles.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.persistence.postgresql/src/test/resources/log4j.xml b/li.strolch.persistence.postgresql/src/test/resources/log4j.xml index 0a2a73d06..7a0499275 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/log4j.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeConfig.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeRoles.xml b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeRoles.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml +++ b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.persistence.xml/pom.xml b/li.strolch.persistence.xml/pom.xml index 9f2b3e728..0eed44edb 100644 --- a/li.strolch.persistence.xml/pom.xml +++ b/li.strolch.persistence.xml/pom.xml @@ -1,35 +1,20 @@ - + + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml - 4.0.0 - li.strolch.persistence.xml - li.strolch.persistence.xml Reference Persistence Implementation for Strolch - - https://github.com/eitchnet/li.strolch.persistence.xml - 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.persistence.xml/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - @@ -41,8 +26,8 @@ li.strolch.agent - ch.eitchnet - ch.eitchnet.xmlpers + li.strolch + li.strolch.xmlpers diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/AbstractDao.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/AbstractDao.java index 932fa2e1a..711f83545 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/AbstractDao.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/AbstractDao.java @@ -23,10 +23,10 @@ import java.util.Set; import li.strolch.model.StrolchElement; import li.strolch.persistence.api.StrolchDao; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.xmlpers.api.PersistenceTransaction; -import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef; -import ch.eitchnet.xmlpers.objref.SubTypeRef; -import ch.eitchnet.xmlpers.objref.TypeRef; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.SubTypeRef; +import li.strolch.xmlpers.objref.TypeRef; public abstract class AbstractDao implements StrolchDao { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlAuditDao.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlAuditDao.java index d135713f5..eace60248 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlAuditDao.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlAuditDao.java @@ -24,13 +24,13 @@ import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditQuery; import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.collections.DateRange; -import ch.eitchnet.xmlpers.api.PersistenceContext; -import ch.eitchnet.xmlpers.api.PersistenceTransaction; -import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef; -import ch.eitchnet.xmlpers.objref.ObjectRef; -import ch.eitchnet.xmlpers.objref.SubTypeRef; -import ch.eitchnet.xmlpers.objref.TypeRef; +import li.strolch.utils.collections.DateRange; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.SubTypeRef; +import li.strolch.xmlpers.objref.TypeRef; /** * @author Robert von Burg diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlPersistenceHandler.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlPersistenceHandler.java index c4f727777..61714539e 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlPersistenceHandler.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlPersistenceHandler.java @@ -18,12 +18,6 @@ package li.strolch.persistence.xml; import java.io.File; import java.util.Properties; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.xmlpers.api.IoMode; -import ch.eitchnet.xmlpers.api.PersistenceConstants; -import ch.eitchnet.xmlpers.api.PersistenceManager; -import ch.eitchnet.xmlpers.api.PersistenceManagerLoader; -import ch.eitchnet.xmlpers.api.PersistenceTransaction; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.api.StrolchRealm; @@ -40,8 +34,14 @@ import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.xml.model.AuditContextFactory; import li.strolch.persistence.xml.model.OrderContextFactory; import li.strolch.persistence.xml.model.ResourceContextFactory; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceManager; +import li.strolch.xmlpers.api.PersistenceManagerLoader; +import li.strolch.xmlpers.api.PersistenceTransaction; /** * @author Robert von Burg diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlStrolchTransaction.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlStrolchTransaction.java index 92098bd6f..02916aa12 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlStrolchTransaction.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/XmlStrolchTransaction.java @@ -20,11 +20,11 @@ import java.util.Set; import li.strolch.agent.api.StrolchRealm; import li.strolch.persistence.api.AbstractTransaction; import li.strolch.persistence.api.PersistenceHandler; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.xmlpers.api.ModificationResult; -import ch.eitchnet.xmlpers.api.PersistenceTransaction; -import ch.eitchnet.xmlpers.api.TransactionResult; +import li.strolch.xmlpers.api.ModificationResult; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.api.TransactionResult; public class XmlStrolchTransaction extends AbstractTransaction { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityContextFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityContextFactory.java index 4b0a90b5a..ad89e27b1 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityContextFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityContextFactory.java @@ -17,11 +17,11 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Tags; import li.strolch.model.activity.Activity; -import ch.eitchnet.xmlpers.api.PersistenceContext; -import ch.eitchnet.xmlpers.api.PersistenceContextFactory; -import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef; -import ch.eitchnet.xmlpers.objref.ObjectRef; -import ch.eitchnet.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; public class ActivityContextFactory implements PersistenceContextFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityDomParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityDomParser.java index 79105de0d..177531365 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityDomParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityDomParser.java @@ -18,11 +18,10 @@ package li.strolch.persistence.xml.model; import li.strolch.model.activity.Activity; import li.strolch.model.xml.ActivityFromDomVisitor; import li.strolch.model.xml.ActivityToDomVisitor; +import li.strolch.xmlpers.api.DomParser; import org.w3c.dom.Document; -import ch.eitchnet.xmlpers.api.DomParser; - public class ActivityDomParser implements DomParser { private Activity activity; diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityParserFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityParserFactory.java index 40707611e..cb0598051 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityParserFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivityParserFactory.java @@ -16,9 +16,9 @@ package li.strolch.persistence.xml.model; import li.strolch.model.activity.Activity; -import ch.eitchnet.xmlpers.api.DomParser; -import ch.eitchnet.xmlpers.api.ParserFactory; -import ch.eitchnet.xmlpers.api.SaxParser; +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.api.ParserFactory; +import li.strolch.xmlpers.api.SaxParser; public class ActivityParserFactory implements ParserFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivitySaxParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivitySaxParser.java index 0833017d5..01f2dc811 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivitySaxParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ActivitySaxParser.java @@ -24,11 +24,10 @@ import li.strolch.model.activity.Activity; import li.strolch.model.xml.ActivityToSaxWriterVisitor; import li.strolch.model.xml.StrolchElementListener; import li.strolch.model.xml.XmlModelSaxReader; +import li.strolch.xmlpers.api.SaxParser; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.xmlpers.api.SaxParser; - /** * @author Robert von Burg */ diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditContextFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditContextFactory.java index 0cad02fb2..5df91789b 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditContextFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditContextFactory.java @@ -17,11 +17,11 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Tags; import li.strolch.model.audit.Audit; -import ch.eitchnet.xmlpers.api.PersistenceContext; -import ch.eitchnet.xmlpers.api.PersistenceContextFactory; -import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef; -import ch.eitchnet.xmlpers.objref.ObjectRef; -import ch.eitchnet.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; public class AuditContextFactory implements PersistenceContextFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditDomParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditDomParser.java index a72e9459d..9d2a0d888 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditDomParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditDomParser.java @@ -18,12 +18,11 @@ package li.strolch.persistence.xml.model; import li.strolch.model.audit.Audit; import li.strolch.model.audit.AuditFromDomReader; import li.strolch.model.audit.AuditToDomVisitor; +import li.strolch.xmlpers.api.DomParser; import org.w3c.dom.Document; import org.w3c.dom.Element; -import ch.eitchnet.xmlpers.api.DomParser; - public class AuditDomParser implements DomParser { private Audit audit; diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditParserFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditParserFactory.java index 67b4f8b66..6e9d78503 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditParserFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/AuditParserFactory.java @@ -16,9 +16,9 @@ package li.strolch.persistence.xml.model; import li.strolch.model.audit.Audit; -import ch.eitchnet.xmlpers.api.DomParser; -import ch.eitchnet.xmlpers.api.ParserFactory; -import ch.eitchnet.xmlpers.api.SaxParser; +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.api.ParserFactory; +import li.strolch.xmlpers.api.SaxParser; public class AuditParserFactory implements ParserFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderContextFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderContextFactory.java index 5a88e0fec..8cc2017bc 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderContextFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderContextFactory.java @@ -17,11 +17,11 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Order; import li.strolch.model.Tags; -import ch.eitchnet.xmlpers.api.PersistenceContext; -import ch.eitchnet.xmlpers.api.PersistenceContextFactory; -import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef; -import ch.eitchnet.xmlpers.objref.ObjectRef; -import ch.eitchnet.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; public class OrderContextFactory implements PersistenceContextFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderDomParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderDomParser.java index 8e0698a75..dc3108ab1 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderDomParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderDomParser.java @@ -18,11 +18,10 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Order; import li.strolch.model.xml.OrderFromDomVisitor; import li.strolch.model.xml.OrderToDomVisitor; +import li.strolch.xmlpers.api.DomParser; import org.w3c.dom.Document; -import ch.eitchnet.xmlpers.api.DomParser; - public class OrderDomParser implements DomParser { private Order order; diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderParserFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderParserFactory.java index f7fc92c66..e3b762103 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderParserFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderParserFactory.java @@ -16,9 +16,9 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Order; -import ch.eitchnet.xmlpers.api.DomParser; -import ch.eitchnet.xmlpers.api.ParserFactory; -import ch.eitchnet.xmlpers.api.SaxParser; +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.api.ParserFactory; +import li.strolch.xmlpers.api.SaxParser; public class OrderParserFactory implements ParserFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderSaxParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderSaxParser.java index f0f923801..2a88f6765 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderSaxParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/OrderSaxParser.java @@ -24,11 +24,10 @@ import li.strolch.model.activity.Activity; import li.strolch.model.xml.OrderToSaxWriterVisitor; import li.strolch.model.xml.StrolchElementListener; import li.strolch.model.xml.XmlModelSaxReader; +import li.strolch.xmlpers.api.SaxParser; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.xmlpers.api.SaxParser; - /** * @author Robert von Burg */ diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceContextFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceContextFactory.java index 408d68db2..e0e50d1fc 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceContextFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceContextFactory.java @@ -17,11 +17,11 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Resource; import li.strolch.model.Tags; -import ch.eitchnet.xmlpers.api.PersistenceContext; -import ch.eitchnet.xmlpers.api.PersistenceContextFactory; -import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef; -import ch.eitchnet.xmlpers.objref.ObjectRef; -import ch.eitchnet.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; public class ResourceContextFactory implements PersistenceContextFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceDomParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceDomParser.java index b79c423fe..fc208e4cd 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceDomParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceDomParser.java @@ -18,11 +18,10 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Resource; import li.strolch.model.xml.ResourceFromDomVisitor; import li.strolch.model.xml.ResourceToDomVisitor; +import li.strolch.xmlpers.api.DomParser; import org.w3c.dom.Document; -import ch.eitchnet.xmlpers.api.DomParser; - public class ResourceDomParser implements DomParser { private Resource resource; diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceParserFactory.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceParserFactory.java index a938584d6..42d6762e9 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceParserFactory.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceParserFactory.java @@ -16,9 +16,9 @@ package li.strolch.persistence.xml.model; import li.strolch.model.Resource; -import ch.eitchnet.xmlpers.api.DomParser; -import ch.eitchnet.xmlpers.api.ParserFactory; -import ch.eitchnet.xmlpers.api.SaxParser; +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.api.ParserFactory; +import li.strolch.xmlpers.api.SaxParser; public class ResourceParserFactory implements ParserFactory { diff --git a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceSaxParser.java b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceSaxParser.java index 9755e6004..31fce9c06 100644 --- a/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceSaxParser.java +++ b/li.strolch.persistence.xml/src/main/java/li/strolch/persistence/xml/model/ResourceSaxParser.java @@ -24,11 +24,10 @@ import li.strolch.model.activity.Activity; import li.strolch.model.xml.ResourceToSaxWriterVisitor; import li.strolch.model.xml.StrolchElementListener; import li.strolch.model.xml.XmlModelSaxReader; +import li.strolch.xmlpers.api.SaxParser; import org.xml.sax.helpers.DefaultHandler; -import ch.eitchnet.xmlpers.api.SaxParser; - /** * @author Robert von Burg */ diff --git a/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ExistingDbTest.java b/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ExistingDbTest.java index ceaa55a36..5afd57ecd 100644 --- a/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ExistingDbTest.java +++ b/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ExistingDbTest.java @@ -23,15 +23,15 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.helper.FileHelper; import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.xml.XmlPersistenceHandler; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.helper.FileHelper; public class ExistingDbTest { diff --git a/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java b/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java index b94b7f7fa..2161966a1 100644 --- a/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java +++ b/li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java @@ -29,8 +29,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.xmlpers.api.ModificationResult; import li.strolch.agent.api.Observer; import li.strolch.agent.api.StrolchRealm; import li.strolch.model.Order; @@ -39,9 +37,11 @@ import li.strolch.model.State; import li.strolch.model.StrolchRootElement; import li.strolch.model.Tags; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.xmlpers.api.ModificationResult; /** * @author Robert von Burg diff --git a/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeConfig.xml b/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeConfig.xml +++ b/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeRoles.xml b/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeRoles.xml +++ b/li.strolch.persistence.xml/src/test/resources/cachedruntime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeConfig.xml b/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeConfig.xml +++ b/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeRoles.xml b/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeRoles.xml +++ b/li.strolch.persistence.xml/src/test/resources/existingDbRuntime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.persistence.xml/src/test/resources/log4j.xml b/li.strolch.persistence.xml/src/test/resources/log4j.xml index 0a2a73d06..7a0499275 100644 --- a/li.strolch.persistence.xml/src/test/resources/log4j.xml +++ b/li.strolch.persistence.xml/src/test/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml b/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml +++ b/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml b/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml +++ b/li.strolch.persistence.xml/src/test/resources/transactionalruntime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.planningwebapp/pom.xml b/li.strolch.planningwebapp/pom.xml index 721a3b53f..7ce396520 100644 --- a/li.strolch.planningwebapp/pom.xml +++ b/li.strolch.planningwebapp/pom.xml @@ -1,60 +1,30 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml + li.strolch.planningwebapp + li.strolch.planningwebapp + Tutorial webapp to show case using Strolch in a servlet container + war + 2011 + - UTF-8 planningwebapp tomcat7.eitchnet.ch http://tomcat.eitchnet.ch:8080/manager/text ${warFinalName} - li.strolch.planningwebapp - li.strolch.planningwebapp - Tutorial webapp to show case using Strolch in a servlet container - war - - https://github.com/eitchnet/li.strolch - - 2011 - - - Github Issues - https://github.com/eitchnet/li.strolch/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - - - - - li.strolch - li.strolch.bom - pom - ${project.version} - - - - - - li.strolch - li.strolch.bom - pom - li.strolch li.strolch.rest diff --git a/li.strolch.planningwebapp/src/main/resources/log4j.xml b/li.strolch.planningwebapp/src/main/resources/log4j.xml index 6bb2f5090..86ea6fcdf 100644 --- a/li.strolch.planningwebapp/src/main/resources/log4j.xml +++ b/li.strolch.planningwebapp/src/main/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml b/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml index 908102df6..515324965 100644 --- a/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml +++ b/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + diff --git a/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml b/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml index 4aec2a73c..f2d4d7742 100644 --- a/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml +++ b/li.strolch.planningwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml @@ -2,7 +2,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.privilege/.gitignore b/li.strolch.privilege/.gitignore new file mode 100644 index 000000000..0f44a0f25 --- /dev/null +++ b/li.strolch.privilege/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.classpath diff --git a/li.strolch.parent/LICENSE b/li.strolch.privilege/LICENSE similarity index 100% rename from li.strolch.parent/LICENSE rename to li.strolch.privilege/LICENSE diff --git a/li.strolch.privilege/README.md b/li.strolch.privilege/README.md new file mode 100644 index 000000000..96303e372 --- /dev/null +++ b/li.strolch.privilege/README.md @@ -0,0 +1,95 @@ +li.strolch.privilege +================== + +[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=li.strolch.privilege)](http://jenkins.eitchnet.ch/view/li.strolch/job/li.strolch.privilege/) + +Overview +======================================================================= + +Privilege is a light weight library to secure access or grant privileges to +users in an application. Privilege allows a developer to secure the application +in different levels of the application providing API's for different +contexts. + +Privilege is implemented in the Java language and is light weight in that it has +no external dependencies other than a Java runtime environment version 6. Since +the JRE 6 has an LDAP implementation it is possible to store Privilege data in +a LDAP repository with only the Privilege JAR. + +Privilege is distributed under the GNU Lesser General Public License on +Github.com and can be downloaded at + + https://github.com/eitchnet/li.strolch.privilege + +The main developer is Robert von Burg who also maintains the +Github repository. He is available for all questions regarding Privilege + +Motivation +======================================================================= +In some cases a developer might want to restrict access to an application +depending on the role which an authenticated user has. In other cases the +developer would need a more finely grained control by restricting access to a +certain object, or a certain method call. + +We were looking for an API which would allows us to restrict access to a given +object in different ways. For instance it was our intention to not simply +restrict access to a specific object type, or instance, but to restrict access +to an instance of the object if it had fields set to a specific value. + +Evaluations on existing libraries which implement access restriction did not +provide an API which suited our needs or which were not easily implemented, thus +leading to the design of Privilege. + +Design Goals +======================================================================= +When a developer needs to implement access restriction an application there are +different questions which the developer will ask: +- Does the user have a specific role? +- Does the user have a specific privilege i.e. is the user allowed to perform a +specific action? +- Is a user allowed to access a specific type of object? +- Is a user allowed to access a specific instance of a type? +- Is a user allowed to access a field on a specific object? + +Privilege's design goals are to allow the developer to answer these questions +with an API which does not mean implementing a lot of additional project +specific code. + +Further in Privilege it should be possible to perform the normal CRUD functions: +- Create users, roles, privileges, etc. +- Read existing users, roles, privileges, etc. +- Update users, roles, privileges, etc. +- Delete users, roles, privileges, etc. + +It should be possible to store Privilege's data in different databases, +depending on the application. For example it should be able to store the data in +XML files, in a LDAP directory and so forth. + +Documentation +======================================================================= + +The current documentation, though a bit outdated, can be found in the docs/ +directory of the Repository + +Compiling +======================================================================= + +Privilege is a Maven3 project and can be built by simply performing the +following command: + +$ mvn compile + +Using +======================================================================= + +To use Privilege see the li.strolch.privilege.test.PrivilegeTest.java class +which contains a few test cases including showing how to load Privilege. + +This documentation is still in need of more work, but for any questions please +don't hesitate to write an e-mail to the developer and we'll find a solution. + + Switzerland, the 29. July 2012 + Robert von Burg + + + diff --git a/li.strolch.privilege/config/PrivilegeConfig.xml b/li.strolch.privilege/config/PrivilegeConfig.xml new file mode 100644 index 000000000..f2f535ce2 --- /dev/null +++ b/li.strolch.privilege/config/PrivilegeConfig.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/li.strolch.privilege/config/PrivilegeConfigMerge.xml b/li.strolch.privilege/config/PrivilegeConfigMerge.xml new file mode 100644 index 000000000..ea847db9b --- /dev/null +++ b/li.strolch.privilege/config/PrivilegeConfigMerge.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/li.strolch.privilege/config/PrivilegeRoles.xml b/li.strolch.privilege/config/PrivilegeRoles.xml new file mode 100644 index 000000000..d3607f38f --- /dev/null +++ b/li.strolch.privilege/config/PrivilegeRoles.xml @@ -0,0 +1,90 @@ + + + + + + Persist + Reload + GetPolicies + + + + true + + + true + + + true + + + true + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + ENABLED + DISABLED + SYSTEM + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + li.strolch.privilege.test.model.TestSystemUserAction + li.strolch.privilege.test.model.TestSystemUserActionDeny + + + true + + + + + + hello + goodbye + + + + \ No newline at end of file diff --git a/li.strolch.privilege/config/PrivilegeRolesMerge.xml b/li.strolch.privilege/config/PrivilegeRolesMerge.xml new file mode 100644 index 000000000..02e9ea037 --- /dev/null +++ b/li.strolch.privilege/config/PrivilegeRolesMerge.xml @@ -0,0 +1,28 @@ + + + + + + allow1 + + + + + true + + + + + + allow1 + deny1 + + + + + allow2 + deny2 + + + + diff --git a/li.strolch.privilege/config/PrivilegeUsers.xml b/li.strolch.privilege/config/PrivilegeUsers.xml new file mode 100644 index 000000000..46b0cdf42 --- /dev/null +++ b/li.strolch.privilege/config/PrivilegeUsers.xml @@ -0,0 +1,39 @@ + + + + + Application + Administrator + ENABLED + en_GB + + PrivilegeAdmin + AppUser + + + + + + + + + System User + Administrator + SYSTEM + en_GB + + system_admin_privileges + + + + + System User + Administrator + SYSTEM + en_GB + + system_admin_privileges + + + + \ No newline at end of file diff --git a/li.strolch.privilege/config/PrivilegeUsersMerge.xml b/li.strolch.privilege/config/PrivilegeUsersMerge.xml new file mode 100644 index 000000000..978464173 --- /dev/null +++ b/li.strolch.privilege/config/PrivilegeUsersMerge.xml @@ -0,0 +1,26 @@ + + + + + System User + Administrator + ENABLED + en_GB + + RoleA1 + RoleA2 + + + + + System User + Administrator + ENABLED + en_GB + + RoleB1 + RoleB2 + + + + \ No newline at end of file diff --git a/li.strolch.privilege/docs/PrivilegeAuthentication.dia b/li.strolch.privilege/docs/PrivilegeAuthentication.dia new file mode 100644 index 000000000..fe9ed43c9 Binary files /dev/null and b/li.strolch.privilege/docs/PrivilegeAuthentication.dia differ diff --git a/li.strolch.privilege/docs/PrivilegeHandlers.dia b/li.strolch.privilege/docs/PrivilegeHandlers.dia new file mode 100644 index 000000000..cf4b84050 Binary files /dev/null and b/li.strolch.privilege/docs/PrivilegeHandlers.dia differ diff --git a/li.strolch.privilege/docs/PrivilegeModelPrivilege.dia b/li.strolch.privilege/docs/PrivilegeModelPrivilege.dia new file mode 100644 index 000000000..8842f4ea4 Binary files /dev/null and b/li.strolch.privilege/docs/PrivilegeModelPrivilege.dia differ diff --git a/li.strolch.privilege/docs/PrivilegeModelUser.dia b/li.strolch.privilege/docs/PrivilegeModelUser.dia new file mode 100644 index 000000000..fca31db1d Binary files /dev/null and b/li.strolch.privilege/docs/PrivilegeModelUser.dia differ diff --git a/li.strolch.privilege/docs/TODO b/li.strolch.privilege/docs/TODO new file mode 100644 index 000000000..e6c36ace6 --- /dev/null +++ b/li.strolch.privilege/docs/TODO @@ -0,0 +1,11 @@ +A list of TODOs for Privilege +============================================ + +- Write up a proper explanation on the idea on how Privilege, PrivilegePolicy, + Restrictable and Roles fit together to grant privileges to Users + +- i18n for any messages and exceptions! + +- Finish the JavaDoc + +- Set up a website =) diff --git a/li.strolch.privilege/pom.xml b/li.strolch.privilege/pom.xml new file mode 100644 index 000000000..a67dd9320 --- /dev/null +++ b/li.strolch.privilege/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + + li.strolch + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml + + + li.strolch + li.strolch.privilege + jar + li.strolch.privilege + 2011 + + + + li.strolch + li.strolch.utils + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.apache.maven.plugins + maven-source-plugin + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.apache.maven.plugins + maven-site-plugin + + + + diff --git a/li.strolch.privilege/privilege.jardesc b/li.strolch.privilege/privilege.jardesc new file mode 100644 index 000000000..d58ef8d02 --- /dev/null +++ b/li.strolch.privilege/privilege.jardesc @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/base/AccessDeniedException.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/AccessDeniedException.java new file mode 100644 index 000000000..c59b9a04e --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/AccessDeniedException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.base; + +/** + * Exception thrown if access is denied during login, or if a certain privilege is not granted + * + * @author Robert von Burg + */ +public class AccessDeniedException extends PrivilegeException { + + private static final long serialVersionUID = 1L; + + /** + * @param msg + * detail on why and where access was denied + */ + public AccessDeniedException(String msg) { + super(msg); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/base/InvalidCredentialsException.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/InvalidCredentialsException.java new file mode 100644 index 000000000..9dcca5b74 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/InvalidCredentialsException.java @@ -0,0 +1,19 @@ +package li.strolch.privilege.base; + +/** + * Exception thrown if the given credentials are invalid + * + * @author Robert von Burg + */ +public class InvalidCredentialsException extends AccessDeniedException { + + private static final long serialVersionUID = 1L; + + /** + * @param msg + * the message to accompany the exception + */ + public InvalidCredentialsException(String msg) { + super(msg); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/base/PrivilegeConflictResolution.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/PrivilegeConflictResolution.java new file mode 100644 index 000000000..5a2cfd089 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/PrivilegeConflictResolution.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.base; + +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; + +/** + * The {@link PrivilegeConflictResolution} defines what should be done if a {@link User} has {@link Role Roles} which + * have Privileges with conflicting names. + * + * @author Robert von Burg + */ +public enum PrivilegeConflictResolution { + + /** + * STRICT requires that a User may not have conflicting Privileges throug multiple Roles. In this case an Exception + * is thrown. + */ + STRICT { + @Override + public boolean isStrict() { + return true; + } + }, + + /** + * MERGE defines that if conflicting privileges are encountered then a merge is to take place. A merge means that if + * all is allowed, then that wins. Otherwise any existing allow and deny lists are merged + */ + MERGE { + @Override + public boolean isStrict() { + return false; + } + }; + + public abstract boolean isStrict(); +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/base/PrivilegeException.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/PrivilegeException.java new file mode 100644 index 000000000..45933786b --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/PrivilegeException.java @@ -0,0 +1,48 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.base; + +/** + * Main {@link RuntimeException} thrown if something goes wrong in Privilege + * + * @author Robert von Burg + */ +public class PrivilegeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * Default constructor + * + * @param string + * message to go with the exception + */ + public PrivilegeException(String string) { + super(string); + } + + /** + * Constructor with underlying exception + * + * @param string + * message to go with the exception + * @param t + * throwable to wrap with this exception which is the underlying exception of this exception + */ + public PrivilegeException(String string, Throwable t) { + super(string, t); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultEncryptionHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultEncryptionHandler.java new file mode 100644 index 000000000..5bab8c615 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultEncryptionHandler.java @@ -0,0 +1,119 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.text.MessageFormat; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * This default {@link EncryptionHandler} creates tokens using a {@link SecureRandom} object. Hashing is done by using + * {@link MessageDigest} and the configured algorithm which is passed in the parameters + *

+ * + * Required parameters: + *
    + *
  • {@link XmlConstants#XML_PARAM_HASH_ALGORITHM}
  • + *
+ * + * @author Robert von Burg + */ +public class DefaultEncryptionHandler implements EncryptionHandler { + + /** + * The log4j logger used in this instance + */ + private static final Logger logger = LoggerFactory.getLogger(DefaultEncryptionHandler.class); + + /** + * The {@link SecureRandom} which is used to create new tokens + */ + private SecureRandom secureRandom; + + /** + * The configured hash algorithm for this instance + */ + private String hashAlgorithm; + + @Override + public String convertToHash(String string) { + return convertToHash(string.getBytes()); + } + + @Override + public String convertToHash(byte[] bytes) { + try { + + return StringHelper.hashAsHex(this.hashAlgorithm, bytes); + + } catch (RuntimeException e) { + if (e.getCause() == null) + throw e; + if (e.getCause().getClass().equals(NoSuchAlgorithmException.class)) + throw new PrivilegeException( + MessageFormat.format("Algorithm {0} was not found!", this.hashAlgorithm), e.getCause()); //$NON-NLS-1$ + if (e.getCause().getClass().equals(UnsupportedEncodingException.class)) + throw new PrivilegeException("Charset ASCII is not supported!", e.getCause()); //$NON-NLS-1$ + + throw e; + } + } + + @Override + public String nextToken() { + byte[] bytes = new byte[16]; + this.secureRandom.nextBytes(bytes); + String randomString = new String(bytes); + return randomString; + } + + @Override + public void initialize(Map parameterMap) { + + this.secureRandom = new SecureRandom(); + + // get hash algorithm parameters + this.hashAlgorithm = parameterMap.get(XmlConstants.XML_PARAM_HASH_ALGORITHM); + if (this.hashAlgorithm == null || this.hashAlgorithm.isEmpty()) { + String msg = "[{0}] Defined parameter {1} is invalid"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), XmlConstants.XML_PARAM_HASH_ALGORITHM); + throw new PrivilegeException(msg); + } + + // test hash algorithm + try { + convertToHash("test"); //$NON-NLS-1$ + DefaultEncryptionHandler.logger.info(MessageFormat + .format("Using hashing algorithm {0}", this.hashAlgorithm)); //$NON-NLS-1$ + } catch (Exception e) { + String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), XmlConstants.XML_PARAM_HASH_ALGORITHM, + e.getLocalizedMessage()); + throw new PrivilegeException(msg, e); + } + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java new file mode 100644 index 000000000..3267ea527 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java @@ -0,0 +1,1770 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.crypto.SecretKey; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.InvalidCredentialsException; +import li.strolch.privilege.base.PrivilegeConflictResolution; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.RoleRep; +import li.strolch.privilege.model.SimpleRestrictable; +import li.strolch.privilege.model.UserRep; +import li.strolch.privilege.model.UserState; +import li.strolch.privilege.model.internal.PrivilegeImpl; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; +import li.strolch.privilege.policy.PrivilegePolicy; +import li.strolch.privilege.xml.CertificateStubsDomWriter; +import li.strolch.privilege.xml.CertificateStubsSaxReader; +import li.strolch.privilege.xml.CertificateStubsSaxReader.CertificateStub; +import li.strolch.utils.collections.Tuple; +import li.strolch.utils.helper.AesCryptoHelper; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * This is default implementation of the {@link PrivilegeHandler} + *

+ * + * The following list describes implementation details: + *
    + *
  • any methods which change the model are first validated by checking if the certificate is for an admin user by + * calling {@link #assertIsPrivilegeAdmin(Certificate)}
  • + *
  • all model requests are delegated to the configured {@link PrivilegeHandler}, except for the session id to + * {@link Certificate} map, no model data is kept in this implementation. This also means that to return the + * representation objects, for every new model query, a new representation object is created
  • + *
  • when creating new users, or editing users then a null password is understood as no password set
  • + *
  • Password requirements are simple: Non null and non empty/length 0
  • + *
+ * + * @author Robert von Burg + */ +public class DefaultPrivilegeHandler implements PrivilegeHandler { + + /** + * slf4j logger + */ + protected static final Logger logger = LoggerFactory.getLogger(DefaultPrivilegeHandler.class); + + /** + * Map keeping a reference to all active sessions + */ + private Map privilegeContextMap; + + /** + * Map of {@link PrivilegePolicy} classes + */ + private Map> policyMap; + + /** + * The persistence handler is used for getting objects and saving changes + */ + private PersistenceHandler persistenceHandler; + + /** + * The encryption handler is used for generating hashes and tokens + */ + private EncryptionHandler encryptionHandler; + + /** + * flag to define if already initialized + */ + private boolean initialized; + + /** + * flag to define if a persist should be performed after a user changes their own data + */ + private boolean autoPersistOnUserChangesData; + + /** + * flag to define if sessions should be persisted + */ + private boolean persistSessions; + + /** + * Path to sessions file for persistence + */ + private File persistSessionsPath; + + /** + * Secret key + */ + private SecretKey secretKey; + + private PrivilegeConflictResolution privilegeConflictResolution; + + @Override + public EncryptionHandler getEncryptionHandler() throws PrivilegeException { + return this.encryptionHandler; + } + + @Override + public RoleRep getRole(Certificate certificate, String roleName) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_GET_ROLE); + + Role role = this.persistenceHandler.getRole(roleName); + if (role == null) + return null; + + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_GET_ROLE, new Tuple(null, role))); + + return role.asRoleRep(); + } + + @Override + public UserRep getUser(Certificate certificate, String username) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_GET_USER); + + User user = this.persistenceHandler.getUser(username); + if (user == null) + return null; + + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_GET_USER, new Tuple(null, user))); + return user.asUserRep(); + } + + @Override + public Map getPolicyDefs(Certificate certificate) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_GET_POLICIES)); + + Map policyDef = new HashMap<>(this.policyMap.size()); + for (Entry> entry : this.policyMap.entrySet()) { + policyDef.put(entry.getKey(), entry.getValue().getName()); + } + return policyDef; + } + + @Override + public List getCertificates(Certificate certificate) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_GET_CERTIFICATES)); + + return this.privilegeContextMap.values().stream().map(p -> p.getCertificate()).collect(Collectors.toList()); + } + + @Override + public List getRoles(Certificate certificate) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_GET_ROLE); + + Stream rolesStream = this.persistenceHandler.getAllRoles().stream(); + + // validate access to each role + // TODO throwing and catching exception ain't cool + rolesStream = rolesStream.filter(role -> { + try { + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_GET_ROLE, new Tuple(null, role))); + return true; + } catch (AccessDeniedException e) { + return false; + } + }); + + List roles = rolesStream.map(r -> r.asRoleRep()).collect(Collectors.toList()); + return roles; + } + + @Override + public List getUsers(Certificate certificate) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_GET_USER); + + Stream usersStream = this.persistenceHandler.getAllUsers().stream(); + + // validate access to each user + // TODO throwing and catching exception ain't cool + usersStream = usersStream.filter(user -> { + try { + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_GET_USER, new Tuple(null, user))); + return true; + } catch (AccessDeniedException e) { + return false; + } + }); + + List users = usersStream.map(u -> u.asUserRep()).collect(Collectors.toList()); + return users; + } + + @Override + public List queryUsers(Certificate certificate, UserRep selectorRep) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_GET_USER); + + String selUserId = selectorRep.getUserId(); + String selUsername = selectorRep.getUsername(); + String selFirstname = selectorRep.getFirstname(); + String selLastname = selectorRep.getLastname(); + UserState selUserState = selectorRep.getUserState(); + Locale selLocale = selectorRep.getLocale(); + Set selRoles = selectorRep.getRoles(); + Map selPropertyMap = selectorRep.getPropertyMap(); + + List result = new ArrayList<>(); + List allUsers = this.persistenceHandler.getAllUsers(); + for (User user : allUsers) { + + // TODO throwing and catching exception ain't cool + try { + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_GET_USER, new Tuple(null, user))); + } catch (AccessDeniedException e) { + continue; + } + + // selections + boolean userIdSelected; + boolean usernameSelected; + boolean firstnameSelected; + boolean lastnameSelected; + boolean userStateSelected; + boolean localeSelected; + boolean roleSelected; + boolean propertySelected; + + // userId + if (selUserId == null) + userIdSelected = true; + else if (selUserId.equals(user.getUserId())) + userIdSelected = true; + else + userIdSelected = false; + + // username + if (selUsername == null) + usernameSelected = true; + else if (selUsername.equals(user.getUsername())) + usernameSelected = true; + else + usernameSelected = false; + + // firstname + if (selFirstname == null) + firstnameSelected = true; + else if (selFirstname.equals(user.getFirstname())) + firstnameSelected = true; + else + firstnameSelected = false; + + // lastname + if (selLastname == null) + lastnameSelected = true; + else if (selLastname.equals(user.getLastname())) + lastnameSelected = true; + else + lastnameSelected = false; + + // user state + if (selUserState == null) + userStateSelected = true; + else if (selUserState.equals(user.getUserState())) + userStateSelected = true; + else + userStateSelected = false; + + // locale + if (selLocale == null) + localeSelected = true; + else if (selLocale.equals(user.getLocale())) + localeSelected = true; + else + localeSelected = false; + + // roles + roleSelected = isSelectedByRole(selRoles, user.getRoles()); + + // properties + propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties()); + + boolean selected = userIdSelected && usernameSelected && firstnameSelected && lastnameSelected + && userStateSelected && localeSelected && roleSelected && propertySelected; + + if (selected) + result.add(user.asUserRep()); + } + + return result; + } + + /** + * Checks if the given properties contains values which are contained in the selectionMap. If the selectionMap is + * null or empty, then true is returned. If a key/value pair from the selectionMap is not in the properties, then + * false is returned + * + * @param selectionMap + * the map defining the expected properties + * @param properties + * the properties which must be a sub set of selectionMap to have this method return true + * + * @return If the selectionMap is null or empty, then true is returned. If a key/value pair from the selectionMap is + * not in the properties, then false is returned + */ + private boolean isSelectedByProperty(Map selectionMap, Map properties) { + + if (selectionMap == null) + return true; + + if (selectionMap.isEmpty() && properties.isEmpty()) + return true; + + for (String selKey : selectionMap.keySet()) { + + String value = properties.get(selKey); + if (value == null || !value.equals(selectionMap.get(selKey))) + return false; + } + + return true; + } + + /** + * Checks if the given roles contains the given selectionRoles, if this is the case, or selectionRoles is null or + * empty, then true is returned, otherwise false + * + * @param selectionRoles + * the required roles + * @param roles + * the roles to check if they contain the selectionRoles + * + * @return Checks if the given roles contains the given selectionRoles, if this is the case, or selectionRoles is + * null or empty, then true is returned, otherwise false + */ + private boolean isSelectedByRole(Set selectionRoles, Set roles) { + + if (selectionRoles == null) + return true; + + return roles.containsAll(selectionRoles); + } + + @Override + public UserRep addUser(Certificate certificate, UserRep userRep, byte[] password) { + try { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_ADD_USER); + + // make sure userId is not set + if (StringHelper.isNotEmpty(userRep.getUserId())) { + String msg = "UserId can not be set when adding a new user!"; + throw new PrivilegeException(MessageFormat.format(msg, userRep.getUsername())); + } + + // set userId + userRep.setUserId(StringHelper.getUniqueId()); + + // first validate user + userRep.validate(); + + validateRolesExist(userRep); + + // validate user does not already exist + if (this.persistenceHandler.getUser(userRep.getUsername()) != null) { + String msg = "User {0} can not be added as it already exists!"; + throw new PrivilegeException(MessageFormat.format(msg, userRep.getUsername())); + } + + String passwordHash = null; + if (password != null) { + + // validate password meets basic requirements + validatePassword(password); + + // hash password + passwordHash = this.encryptionHandler.convertToHash(password); + } + + // create new user + User newUser = createUser(userRep, passwordHash); + + // detect privilege conflicts + assertNoPrivilegeConflict(newUser); + + // validate this user may create such a user + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ADD_USER, new Tuple(null, newUser))); + + // delegate to persistence handler + this.persistenceHandler.addUser(newUser); + + return newUser.asUserRep(); + + } finally { + clearPassword(password); + } + } + + @Override + public UserRep replaceUser(Certificate certificate, UserRep userRep, byte[] password) { + try { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_MODIFY_USER); + + // first validate user + userRep.validate(); + + validateRolesExist(userRep); + + // validate user exists + User existingUser = this.persistenceHandler.getUser(userRep.getUsername()); + if (existingUser == null) { + String msg = "User {0} can not be replaced as it does not exist!"; + throw new PrivilegeException(MessageFormat.format(msg, userRep.getUsername())); + } + + // validate same userId + if (!existingUser.getUserId().equals(userRep.getUserId())) { + String msg = "UserId of existing user {0} does not match userRep {1}"; + msg = MessageFormat.format(msg, existingUser.getUserId(), userRep.getUserId()); + throw new PrivilegeException(MessageFormat.format(msg, userRep.getUsername())); + } + + String passwordHash = null; + if (password != null) { + + // validate password meets basic requirements + validatePassword(password); + + // hash password + passwordHash = this.encryptionHandler.convertToHash(password); + } + + User newUser = createUser(userRep, passwordHash); + + // detect privilege conflicts + assertNoPrivilegeConflict(newUser); + + // validate this user may modify this user + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_MODIFY_USER, new Tuple(existingUser, newUser))); + + // delegate to persistence handler + this.persistenceHandler.replaceUser(newUser); + + return newUser.asUserRep(); + + } finally { + clearPassword(password); + } + } + + private void validateRolesExist(UserRep userRep) { + // validate all roles exist + for (String role : userRep.getRoles()) { + if (this.persistenceHandler.getRole(role) == null) { + String msg = "Can not add user {0} as role {1} does not exist!"; + msg = MessageFormat.format(msg, userRep.getUsername(), role); + throw new PrivilegeException(msg); + } + } + } + + private User createUser(UserRep userRep, String passwordHash) { + User user = new User(userRep.getUserId(), userRep.getUsername(), passwordHash, userRep.getFirstname(), + userRep.getLastname(), userRep.getUserState(), userRep.getRoles(), userRep.getLocale(), + userRep.getPropertyMap()); + return user; + } + + @Override + public UserRep updateUser(Certificate certificate, UserRep userRep) + throws AccessDeniedException, PrivilegeException { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_MODIFY_USER); + + // get existing user + User existingUser = this.persistenceHandler.getUser(userRep.getUsername()); + if (existingUser == null) { + throw new PrivilegeException(MessageFormat.format("User {0} does not exist!", userRep.getUsername())); //$NON-NLS-1$ + } + + // if nothing to do, then stop + if (StringHelper.isEmpty(userRep.getFirstname()) && StringHelper.isEmpty(userRep.getLastname()) + && userRep.getLocale() == null + && (userRep.getProperties() == null || userRep.getProperties().isEmpty())) { + throw new PrivilegeException(MessageFormat.format("All updateable fields are empty for update of user {0}", //$NON-NLS-1$ + userRep.getUsername())); + } + + String userId = existingUser.getUserId(); + String username = existingUser.getUsername(); + String password = existingUser.getPassword(); + String firstname = existingUser.getFirstname(); + String lastname = existingUser.getLastname(); + UserState userState = existingUser.getUserState(); + Set roles = existingUser.getRoles(); + Locale locale = existingUser.getLocale(); + Map propertyMap = existingUser.getProperties(); + + // get updated fields + if (StringHelper.isNotEmpty(userRep.getFirstname())) + firstname = userRep.getFirstname(); + if (StringHelper.isNotEmpty(userRep.getLastname())) + lastname = userRep.getLastname(); + if (userRep.getLocale() != null) + locale = userRep.getLocale(); + if (userRep.getProperties() != null && !userRep.getProperties().isEmpty()) + propertyMap = userRep.getPropertyMap(); + + // create new user + User newUser = new User(userId, username, password, firstname, lastname, userState, roles, locale, propertyMap); + + // detect privilege conflicts + assertNoPrivilegeConflict(newUser); + + // validate this user may modify this user + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_MODIFY_USER, new Tuple(existingUser, newUser))); + + // delegate to persistence handler + this.persistenceHandler.replaceUser(newUser); + + return newUser.asUserRep(); + } + + @Override + public UserRep removeUser(Certificate certificate, String username) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_REMOVE_USER); + + // validate user exists + User existingUser = this.persistenceHandler.getUser(username); + if (existingUser == null) { + String msg = "Can not remove User {0} because user does not exist!"; + throw new PrivilegeException(MessageFormat.format(msg, username)); + } + + // validate this user may remove this user + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_REMOVE_USER, new Tuple(null, existingUser))); + + // delegate user removal to persistence handler + this.persistenceHandler.removeUser(username); + + return existingUser.asUserRep(); + } + + @Override + public UserRep addRoleToUser(Certificate certificate, String username, String roleName) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_ADD_ROLE_TO_USER); + + // get user + User existingUser = this.persistenceHandler.getUser(username); + if (existingUser == null) { + throw new PrivilegeException(MessageFormat.format("User {0} does not exist!", username)); //$NON-NLS-1$ + } + + // validate that this user may add this role to this user + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ADD_ROLE_TO_USER, new Tuple(existingUser, roleName))); + + // check that user not already has role + Set currentRoles = existingUser.getRoles(); + if (currentRoles.contains(roleName)) { + String msg = MessageFormat.format("User {0} already has role {1}", username, roleName); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // validate that the role exists + if (this.persistenceHandler.getRole(roleName) == null) { + String msg = MessageFormat.format("Role {0} does not exist!", roleName); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // create new user + Set newRoles = new HashSet<>(currentRoles); + newRoles.add(roleName); + + User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), + existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(), newRoles, + existingUser.getLocale(), existingUser.getProperties()); + + // detect privilege conflicts + assertNoPrivilegeConflict(newUser); + + // delegate user replacement to persistence handler + this.persistenceHandler.replaceUser(newUser); + + return newUser.asUserRep(); + } + + @Override + public UserRep removeRoleFromUser(Certificate certificate, String username, String roleName) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_REMOVE_ROLE_FROM_USER); + + // get User + User existingUser = this.persistenceHandler.getUser(username); + if (existingUser == null) { + throw new PrivilegeException(MessageFormat.format("User {0} does not exist!", username)); //$NON-NLS-1$ + } + + // validate that this user may remove this role from this user + prvCtx.validateAction( + new SimpleRestrictable(PRIVILEGE_REMOVE_ROLE_FROM_USER, new Tuple(existingUser, roleName))); + + // ignore if user does not have role + Set currentRoles = existingUser.getRoles(); + if (!currentRoles.contains(roleName)) { + String msg = MessageFormat.format("User {0} does not have role {1}", existingUser.getUsername(), roleName); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // create new user + Set newRoles = new HashSet<>(currentRoles); + newRoles.remove(roleName); + User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), + existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(), newRoles, + existingUser.getLocale(), existingUser.getProperties()); + + // delegate user replacement to persistence handler + this.persistenceHandler.replaceUser(newUser); + + return newUser.asUserRep(); + } + + @Override + public UserRep setUserLocale(Certificate certificate, String username, Locale locale) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_SET_USER_LOCALE); + + // get User + User existingUser = this.persistenceHandler.getUser(username); + if (existingUser == null) { + throw new PrivilegeException(MessageFormat.format("User {0} does not exist!", username)); //$NON-NLS-1$ + } + + // create new user + User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), + existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(), + existingUser.getRoles(), locale, existingUser.getProperties()); + + // if the user is not setting their own locale, then make sure this user may set this user's locale + if (!certificate.getUsername().equals(username)) { + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_SET_USER_LOCALE, new Tuple(existingUser, newUser))); + } + + // delegate user replacement to persistence handler + this.persistenceHandler.replaceUser(newUser); + + // perform automatic persisting, if enabled + if (this.autoPersistOnUserChangesData) { + this.persistenceHandler.persist(); + } + + return newUser.asUserRep(); + } + + @Override + public void setUserPassword(Certificate certificate, String username, byte[] password) { + try { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_SET_USER_PASSWORD); + + // get User + User existingUser = this.persistenceHandler.getUser(username); + if (existingUser == null) { + throw new PrivilegeException(MessageFormat.format("User {0} does not exist!", username)); //$NON-NLS-1$ + } + + String passwordHash = null; + if (password != null) { + + // validate password meets basic requirements + validatePassword(password); + + // hash password + passwordHash = this.encryptionHandler.convertToHash(password); + } + + // create new user + User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), passwordHash, + existingUser.getFirstname(), existingUser.getLastname(), existingUser.getUserState(), + existingUser.getRoles(), existingUser.getLocale(), existingUser.getProperties()); + + // if the user is not setting their own password, then make sure this user may set this user's password + if (!certificate.getUsername().equals(username)) { + prvCtx.validateAction( + new SimpleRestrictable(PRIVILEGE_SET_USER_PASSWORD, new Tuple(existingUser, newUser))); + } + + // delegate user replacement to persistence handler + this.persistenceHandler.replaceUser(newUser); + + // perform automatic persisting, if enabled + if (this.autoPersistOnUserChangesData) { + this.persistenceHandler.persist(); + } + + } finally { + clearPassword(password); + } + } + + @Override + public UserRep setUserState(Certificate certificate, String username, UserState state) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_SET_USER_STATE); + + // get User + User existingUser = this.persistenceHandler.getUser(username); + if (existingUser == null) { + throw new PrivilegeException(MessageFormat.format("User {0} does not exist!", username)); //$NON-NLS-1$ + } + + // create new user + User newUser = new User(existingUser.getUserId(), existingUser.getUsername(), existingUser.getPassword(), + existingUser.getFirstname(), existingUser.getLastname(), state, existingUser.getRoles(), + existingUser.getLocale(), existingUser.getProperties()); + + // validate that this user may modify this user's state + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_SET_USER_STATE, new Tuple(existingUser, newUser))); + + // delegate user replacement to persistence handler + this.persistenceHandler.replaceUser(newUser); + + return newUser.asUserRep(); + } + + @Override + public RoleRep addRole(Certificate certificate, RoleRep roleRep) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_ADD_ROLE); + + // first validate role + roleRep.validate(); + + // validate role does not exist + if (this.persistenceHandler.getRole(roleRep.getName()) != null) { + String msg = MessageFormat.format("Can not add role {0} as it already exists!", roleRep.getName()); + throw new PrivilegeException(msg); + } + + // create new role from RoleRep + Role newRole = new Role(roleRep); + + // validate that this user may add this new role + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ADD_ROLE, new Tuple(null, newRole))); + + // validate policy if not null + validatePolicies(newRole); + + // delegate to persistence handler + this.persistenceHandler.addRole(newRole); + + return newRole.asRoleRep(); + } + + @Override + public RoleRep replaceRole(Certificate certificate, RoleRep roleRep) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_MODIFY_ROLE); + + // first validate role + roleRep.validate(); + + // validate role does exist + Role existingRole = this.persistenceHandler.getRole(roleRep.getName()); + if (existingRole == null) { + String msg = MessageFormat.format("Can not replace role {0} as it does not exist!", roleRep.getName()); + throw new PrivilegeException(msg); + } + + // create new role from RoleRep + Role newRole = new Role(roleRep); + + // detect privilege conflicts + assertNoPrivilegeConflict(newRole); + + // validate that this user may modify this role + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_MODIFY_ROLE, new Tuple(existingRole, newRole))); + + // validate policy if not null + validatePolicies(newRole); + + // delegate to persistence handler + this.persistenceHandler.replaceRole(newRole); + + return newRole.asRoleRep(); + } + + @Override + public RoleRep removeRole(Certificate certificate, String roleName) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_REMOVE_ROLE); + + // validate no user is using this role + Set roles = new HashSet<>(Arrays.asList(roleName)); + UserRep selector = new UserRep(null, null, null, null, null, roles, null, null); + List usersWithRole = queryUsers(certificate, selector); + if (!usersWithRole.isEmpty()) { + String usersS = usersWithRole.stream().map(UserRep::getUsername).collect(Collectors.joining(", ")); + String msg = "The role {0} can not be removed as the following {1} user have the role assigned: {2}"; + msg = MessageFormat.format(msg, roleName, usersWithRole.size(), usersS); + throw new PrivilegeException(msg); + } + + // validate role exists + Role existingRole = this.persistenceHandler.getRole(roleName); + if (existingRole == null) { + String msg = "Can not remove Role {0} because role does not exist!"; + throw new PrivilegeException(MessageFormat.format(msg, roleName)); + } + + // validate that this user may remove this role + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_REMOVE_ROLE, new Tuple(null, existingRole))); + + // delegate role removal to persistence handler + this.persistenceHandler.removeRole(roleName); + + return existingRole.asRoleRep(); + } + + @Override + public RoleRep addOrReplacePrivilegeOnRole(Certificate certificate, String roleName, PrivilegeRep privilegeRep) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_MODIFY_ROLE); + + // validate PrivilegeRep + privilegeRep.validate(); + + // get role + Role existingRole = this.persistenceHandler.getRole(roleName); + if (existingRole == null) { + String msg = MessageFormat.format("Role {0} does not exist!", roleName); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // validate that policy exists if needed + String policy = privilegeRep.getPolicy(); + if (policy != null && !this.policyMap.containsKey(policy)) { + String msg = "Policy {0} for Privilege {1} does not exist"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, policy, privilegeRep.getName()); + throw new PrivilegeException(msg); + } + + // create new role with the additional privilege + IPrivilege newPrivilege = new PrivilegeImpl(privilegeRep); + + // copy existing privileges + Set existingPrivilegeNames = existingRole.getPrivilegeNames(); + Map privilegeMap = new HashMap<>(existingPrivilegeNames.size() + 1); + for (String name : existingPrivilegeNames) { + IPrivilege privilege = existingRole.getPrivilege(name); + privilegeMap.put(name, privilege); + } + + // add new one + privilegeMap.put(newPrivilege.getName(), newPrivilege); + + // create new role + Role newRole = new Role(existingRole.getName(), privilegeMap); + + // detect privilege conflicts + assertNoPrivilegeConflict(newRole); + + // validate that this user may modify this role + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_MODIFY_ROLE, new Tuple(existingRole, newRole))); + + // delegate role replacement to persistence handler + this.persistenceHandler.replaceRole(newRole); + + return newRole.asRoleRep(); + } + + @Override + public RoleRep removePrivilegeFromRole(Certificate certificate, String roleName, String privilegeName) { + + // validate user actually has this type of privilege + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.assertHasPrivilege(PRIVILEGE_MODIFY_ROLE); + + // get role + Role existingRole = this.persistenceHandler.getRole(roleName); + if (existingRole == null) { + throw new PrivilegeException(MessageFormat.format("Role {0} does not exist!", roleName)); //$NON-NLS-1$ + } + + // ignore if role does not have privilege + if (!existingRole.hasPrivilege(privilegeName)) { + String msg = MessageFormat.format("Role {0} does not have Privilege {1}", roleName, privilegeName); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // create new set of privileges with out the to removed privilege + Set privilegeNames = existingRole.getPrivilegeNames(); + Map newPrivileges = new HashMap<>(privilegeNames.size() - 1); + for (String name : privilegeNames) { + IPrivilege privilege = existingRole.getPrivilege(name); + if (!privilege.getName().equals(privilegeName)) + newPrivileges.put(privilege.getName(), privilege); + } + + // create new role + Role newRole = new Role(existingRole.getName(), newPrivileges); + + // validate that this user may modify this role + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_MODIFY_ROLE, new Tuple(existingRole, newRole))); + + // delegate user replacement to persistence handler + this.persistenceHandler.replaceRole(newRole); + + return newRole.asRoleRep(); + } + + @Override + public Certificate authenticate(String username, byte[] password) { + + try { + // username must be at least 2 characters in length + if (username == null || username.length() < 2) { + String msg = MessageFormat.format("The given username ''{0}'' is shorter than 2 characters", username); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // check the password + User user = checkCredentialsAndUserState(username, password); + + // validate user has at least one role + Set userRoles = user.getRoles(); + if (userRoles.isEmpty()) { + throw new PrivilegeException( + MessageFormat.format("User {0} does not have any roles defined!", username)); //$NON-NLS-1$ + } + + // get 2 auth tokens + String authToken = this.encryptionHandler.convertToHash(this.encryptionHandler.nextToken()); + + // get next session id + String sessionId = UUID.randomUUID().toString(); + + // create a new certificate, with details of the user + Certificate certificate = new Certificate(sessionId, username, user.getFirstname(), user.getLastname(), + user.getUserState(), authToken, new Date(), user.getLocale(), userRoles, + new HashMap<>(user.getProperties())); + certificate.setLastAccess(new Date()); + + PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user); + this.privilegeContextMap.put(sessionId, privilegeContext); + + persistSessions(); + + // log + DefaultPrivilegeHandler.logger + .info(MessageFormat.format("User {0} authenticated: {1}", username, certificate)); //$NON-NLS-1$ + + // return the certificate + return certificate; + + } catch (RuntimeException e) { + String msg = "User {0} Failed to authenticate: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, username, e.getMessage()); + DefaultPrivilegeHandler.logger.error(msg); + throw e; + } finally { + clearPassword(password); + } + } + + private boolean persistSessions() { + if (!this.persistSessions) + return false; + + List sessions = this.privilegeContextMap.values().stream().map(p -> p.getCertificate()) + .filter(c -> !c.getUserState().isSystem()).collect(Collectors.toList()); + + try (FileOutputStream fout = new FileOutputStream(this.persistSessionsPath); + OutputStream outputStream = AesCryptoHelper.wrapEncrypt(this.secretKey, fout)) { + + CertificateStubsDomWriter writer = new CertificateStubsDomWriter(sessions, outputStream); + writer.write(); + outputStream.flush(); + + } catch (Exception e) { + throw new PrivilegeException("Failed to persist sessions!", e); + } + + return true; + } + + private boolean loadSessions() { + if (!this.persistSessions) { + logger.info("Persisteding of sessions not enabled, so not loading!."); + return false; + } + + if (!this.persistSessionsPath.exists()) { + logger.info("No persisted sessions exist to be loaded."); + return false; + } + + if (!this.persistSessionsPath.isFile()) + throw new PrivilegeException( + "Sessions data file is not a file but exists at " + this.persistSessionsPath.getAbsolutePath()); + + List certificateStubs; + try (FileInputStream fin = new FileInputStream(this.persistSessionsPath); + InputStream inputStream = AesCryptoHelper.wrapDecrypt(this.secretKey, fin)) { + + CertificateStubsSaxReader reader = new CertificateStubsSaxReader(inputStream); + certificateStubs = reader.read(); + + } catch (Exception e) { + logger.error("Failed to load sessions!", e); + this.persistSessionsPath.delete(); + return false; + } + + if (certificateStubs.isEmpty()) { + logger.info("No persisted sessions exist to be loaded."); + return false; + } + + for (CertificateStub certificateStub : certificateStubs) { + String username = certificateStub.getUsername(); + String sessionId = certificateStub.getSessionId(); + String authToken = certificateStub.getAuthToken(); + User user = this.persistenceHandler.getUser(username); + if (user == null) { + logger.error("Ignoring session data for missing user " + username); + continue; + } + + Set userRoles = user.getRoles(); + if (userRoles.isEmpty()) { + logger.error("Ignoring session data for user " + username + " which has not roles defined!"); + continue; + } + + // create a new certificate, with details of the user + Certificate certificate = new Certificate(sessionId, username, user.getFirstname(), user.getLastname(), + user.getUserState(), authToken, certificateStub.getLoginTime(), certificateStub.getLocale(), + userRoles, new HashMap<>(user.getProperties())); + certificate.setLastAccess(certificateStub.getLastAccess()); + + PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user); + this.privilegeContextMap.put(sessionId, privilegeContext); + } + + logger.info("Loaded " + this.privilegeContextMap.size() + " sessions."); + return true; + } + + /** + * Checks the credentials and validates that the user may log in. + * + * @param username + * the username of the {@link User} to check against + * @param password + * the password of this user + * + * @return the {@link User} if the credentials are valid and the user may login + * + * @throws AccessDeniedException + * if anything is wrong with the credentials or the user state + * @throws InvalidCredentialsException + * if the given credentials are invalid, the user does not exist, or has no password set + */ + private User checkCredentialsAndUserState(String username, byte[] password) + throws InvalidCredentialsException, AccessDeniedException { + + // and validate the password + validatePassword(password); + + // we only work with hashed passwords + String passwordHash = this.encryptionHandler.convertToHash(password); + + // get user object + User user = this.persistenceHandler.getUser(username); + // no user means no authentication + if (user == null) { + String msg = MessageFormat.format("There is no user defined with the username {0}", username); //$NON-NLS-1$ + throw new InvalidCredentialsException(msg); + } + + // make sure not a system user - they may not login in + if (user.getUserState() == UserState.SYSTEM) { + String msg = "User {0} is a system user and may not login!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, username); + throw new InvalidCredentialsException(msg); + } + + // validate password + String pwHash = user.getPassword(); + if (pwHash == null) + throw new AccessDeniedException( + MessageFormat.format("User {0} has no password and may not login!", username)); //$NON-NLS-1$ + if (!pwHash.equals(passwordHash)) + throw new InvalidCredentialsException(MessageFormat.format("Password is incorrect for {0}", username)); //$NON-NLS-1$ + + // validate if user is allowed to login + // this also capture the trying to login of SYSTEM user + if (user.getUserState() != UserState.ENABLED) { + String msg = "User {0} does not have state {1} and can not login!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, username, UserState.ENABLED); + throw new AccessDeniedException(msg); + } + + return user; + } + + /** + * Builds a {@link PrivilegeContext} for the given {@link User} and its {@link Certificate} + * + * @param certificate + * @param user + * + * @return + */ + private PrivilegeContext buildPrivilegeContext(Certificate certificate, User user) { + + Set userRoles = user.getRoles(); + Map privileges = new HashMap<>(); + Map policies = new HashMap<>(); + + // get a cache of the privileges and policies for this user + for (String roleName : userRoles) { + Role role = this.persistenceHandler.getRole(roleName); + Set privilegeNames = role.getPrivilegeNames(); + for (String privilegeName : privilegeNames) { + + IPrivilege privilege = role.getPrivilege(privilegeName); + if (privilege == null) { + String msg = "The Privilege {0} does not exist for role {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName, roleName); + throw new PrivilegeException(msg); + } + + // cache the privilege + if (privileges.containsKey(privilegeName)) { + if (this.privilegeConflictResolution.isStrict()) { + String msg = "User has conflicts for privilege {0} with role {1}"; + msg = MessageFormat.format(msg, privilegeName, roleName); + throw new PrivilegeException(msg); + } + + IPrivilege priv = privileges.get(privilegeName); + boolean allAllowed = priv.isAllAllowed() || privilege.isAllAllowed(); + Set allowList; + Set denyList; + if (allAllowed) { + allowList = Collections.emptySet(); + denyList = Collections.emptySet(); + } else { + allowList = new HashSet<>(priv.getAllowList()); + allowList.addAll(privilege.getAllowList()); + denyList = new HashSet<>(priv.getDenyList()); + denyList.addAll(privilege.getDenyList()); + } + priv = new PrivilegeImpl(priv.getName(), priv.getPolicy(), allAllowed, denyList, allowList); + + privileges.put(privilegeName, priv); + continue; + } + + privileges.put(privilegeName, privilege); + + // cache the policy for the privilege + String policyName = privilege.getPolicy(); + if (policies.containsKey(policyName)) + continue; + + PrivilegePolicy policy = getPolicy(policyName); + if (policy == null) { + String msg = "The Policy {0} does not exist for Privilege {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, policyName, privilegeName); + throw new PrivilegeException(msg); + } + policies.put(policyName, policy); + } + } + + UserRep userRep = user.asUserRep(); + PrivilegeContext privilegeContext = new PrivilegeContext(userRep, certificate, privileges, policies); + return privilegeContext; + } + + @Override + public boolean invalidateSession(Certificate certificate) { + + // first validate certificate + isCertificateValid(certificate); + + // remove registration + PrivilegeContext privilegeContext = this.privilegeContextMap.remove(certificate.getSessionId()); + + // persist sessions + persistSessions(); + + // return true if object was really removed + boolean loggedOut = privilegeContext != null; + if (loggedOut) + DefaultPrivilegeHandler.logger + .info(MessageFormat.format("User {0} logged out.", certificate.getUsername())); //$NON-NLS-1$ + else + DefaultPrivilegeHandler.logger.warn("User already logged out!"); //$NON-NLS-1$ + return loggedOut; + } + + @Override + public void isCertificateValid(Certificate certificate) { + + // certificate must not be null + if (certificate == null) + throw new PrivilegeException("Certificate may not be null!"); //$NON-NLS-1$ + + // first see if a session exists for this certificate + PrivilegeContext privilegeContext = this.privilegeContextMap.get(certificate.getSessionId()); + if (privilegeContext == null) { + String msg = MessageFormat.format("There is no session information for {0}", certificate); //$NON-NLS-1$ + throw new AccessDeniedException(msg); + } + + // validate certificate has not been tampered with + Certificate sessionCertificate = privilegeContext.getCertificate(); + if (!sessionCertificate.equals(certificate)) { + String msg = "Received illegal certificate for session id {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, certificate.getSessionId()); + throw new PrivilegeException(msg); + } + + // get user object + User user = this.persistenceHandler.getUser(privilegeContext.getUsername()); + + // if user exists, then certificate is valid + if (user == null) { + String msg = "Oh boy, how did this happen: No User in user map although the certificate is valid!"; //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // everything is ok + } + + @Override + public void checkPassword(Certificate certificate, byte[] password) throws PrivilegeException { + try { + isCertificateValid(certificate); + checkCredentialsAndUserState(certificate.getUsername(), password); + } finally { + clearPassword(password); + } + } + + @Override + public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException { + + // first validate certificate + isCertificateValid(certificate); + + return this.privilegeContextMap.get(certificate.getSessionId()); + } + + /** + * This simple implementation validates that the password is not null, and that the password string is not empty + * + * @see li.strolch.privilege.handler.PrivilegeHandler#validatePassword(byte[]) + */ + @Override + public void validatePassword(byte[] password) throws PrivilegeException { + + if (password == null || password.length == 0) { + throw new PrivilegeException("A password may not be empty!"); //$NON-NLS-1$ + } + + if (password.length < 3) { + throw new PrivilegeException("The given password is shorter than 3 characters"); //$NON-NLS-1$ + } + } + + @Override + public boolean persist(Certificate certificate) { + + // validate who is doing this + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_PERSIST)); + + return this.persistenceHandler.persist(); + } + + @Override + public boolean persistSessions(Certificate certificate) { + + // validate who is doing this + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_PERSIST_SESSIONS)); + + return persistSessions(); + } + + @Override + public boolean reload(Certificate certificate) { + + // validate who is doing this + PrivilegeContext prvCtx = getPrivilegeContext(certificate); + prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_RELOAD)); + + return this.persistenceHandler.reload(); + } + + /** + * Initializes the concrete {@link EncryptionHandler}. The passed parameter map contains any configuration this + * {@link PrivilegeHandler} might need. This method may only be called once and this must be enforced by the + * concrete implementation + * + * @param parameterMap + * a map containing configuration properties + * @param encryptionHandler + * the {@link EncryptionHandler} instance for this {@link PrivilegeHandler} + * @param persistenceHandler + * the {@link PersistenceHandler} instance for this {@link PrivilegeHandler} + * @param policyMap + * map of {@link PrivilegePolicy} classes + * + * @throws PrivilegeException + * if the this method is called multiple times or an initialization exception occurs + */ + public synchronized void initialize(Map parameterMap, EncryptionHandler encryptionHandler, + PersistenceHandler persistenceHandler, Map> policyMap) { + + if (this.initialized) + throw new PrivilegeException("Already initialized!"); //$NON-NLS-1$ + + this.policyMap = policyMap; + this.encryptionHandler = encryptionHandler; + this.persistenceHandler = persistenceHandler; + + handleAutoPersistOnUserDataChange(parameterMap); + handlePersistSessionsParam(parameterMap); + handleConflictResolutionParam(parameterMap); + handleSecretParams(parameterMap); + + // validate policies on privileges of Roles + for (Role role : persistenceHandler.getAllRoles()) { + validatePolicies(role); + } + + // validate privilege conflicts + validatePrivilegeConflicts(); + + this.privilegeContextMap = Collections.synchronizedMap(new HashMap()); + + loadSessions(); + + this.initialized = true; + } + + private void handleAutoPersistOnUserDataChange(Map parameterMap) { + String autoPersistS = parameterMap.get(PARAM_AUTO_PERSIST_ON_USER_CHANGES_DATA); + if (StringHelper.isEmpty(autoPersistS) || autoPersistS.equals(Boolean.FALSE.toString())) { + this.autoPersistOnUserChangesData = false; + } else if (autoPersistS.equals(Boolean.TRUE.toString())) { + this.autoPersistOnUserChangesData = true; + logger.info("Enabling automatic persistence when user changes their data."); //$NON-NLS-1$ + } else { + String msg = "Parameter {0} has illegal value {1}. Overriding with {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_AUTO_PERSIST_ON_USER_CHANGES_DATA, autoPersistS, Boolean.FALSE); + logger.error(msg); + this.autoPersistOnUserChangesData = false; + } + } + + private void handlePersistSessionsParam(Map parameterMap) { + String persistSessionsS = parameterMap.get(PARAM_PERSIST_SESSIONS); + if (StringHelper.isEmpty(persistSessionsS) || persistSessionsS.equals(Boolean.FALSE.toString())) { + this.persistSessions = false; + } else if (persistSessionsS.equals(Boolean.TRUE.toString())) { + this.persistSessions = true; + + String persistSessionsPathS = parameterMap.get(PARAM_PERSIST_SESSIONS_PATH); + if (StringHelper.isEmpty(persistSessionsPathS)) { + String msg = "Parameter {0} has illegal value {1}."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_PERSIST_SESSIONS_PATH, persistSessionsPathS); + throw new PrivilegeException(msg); + } + + File persistSessionsPath = new File(persistSessionsPathS); + if (!persistSessionsPath.getParentFile().isDirectory()) { + String msg = "Path for param {0} is invalid as parent does not exist or is not a directory. Value: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_PERSIST_SESSIONS_PATH, persistSessionsPath.getAbsolutePath()); + throw new PrivilegeException(msg); + } + + if (persistSessionsPath.exists() && (!persistSessionsPath.isFile() || !persistSessionsPath.canWrite())) { + String msg = "Path for param {0} is invalid as file exists but is not a file or not writeable. Value: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_PERSIST_SESSIONS_PATH, persistSessionsPath.getAbsolutePath()); + throw new PrivilegeException(msg); + } + + this.persistSessionsPath = persistSessionsPath; + logger.info(MessageFormat.format("Enabling persistence of sessions to {0}", //$NON-NLS-1$ + this.persistSessionsPath.getAbsolutePath())); + } else { + String msg = "Parameter {0} has illegal value {1}. Overriding with {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_PERSIST_SESSIONS, persistSessionsS, Boolean.FALSE); + logger.error(msg); + this.persistSessions = false; + } + } + + private void handleConflictResolutionParam(Map parameterMap) { + String privilegeConflictResolutionS = parameterMap.get(PARAM_PRIVILEGE_CONFLICT_RESOLUTION); + if (privilegeConflictResolutionS == null) { + this.privilegeConflictResolution = PrivilegeConflictResolution.STRICT; + String msg = "No {0} parameter defined. Using {1}"; + msg = MessageFormat.format(msg, PARAM_PRIVILEGE_CONFLICT_RESOLUTION, this.privilegeConflictResolution); + logger.info(msg); + } else { + try { + this.privilegeConflictResolution = PrivilegeConflictResolution.valueOf(privilegeConflictResolutionS); + } catch (Exception e) { + String msg = "Parameter {0} has illegal value {1}."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_PRIVILEGE_CONFLICT_RESOLUTION, privilegeConflictResolutionS); + throw new PrivilegeException(msg); + } + } + logger.info("Privilege conflict resolution set to " + this.privilegeConflictResolution); //$NON-NLS-1$ + } + + private void handleSecretParams(Map parameterMap) { + + if (!this.persistSessions) + return; + + String secretKeyS = parameterMap.get(PARAM_SECRET_KEY); + if (StringHelper.isEmpty(secretKeyS)) { + String msg = "Parameter {0} may not be empty if parameter {1} is enabled."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_SECRET_KEY, PARAM_PRIVILEGE_CONFLICT_RESOLUTION); + throw new PrivilegeException(msg); + } + + String secretSaltS = parameterMap.get(PARAM_SECRET_SALT); + if (StringHelper.isEmpty(secretSaltS)) { + String msg = "Parameter {0} may not be empty if parameter {1} is enabled."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PARAM_SECRET_SALT, PARAM_PRIVILEGE_CONFLICT_RESOLUTION); + throw new PrivilegeException(msg); + } + + this.secretKey = AesCryptoHelper.buildSecret(secretKeyS.toCharArray(), secretSaltS.getBytes()); + } + + private void validatePrivilegeConflicts() { + if (!this.privilegeConflictResolution.isStrict()) { + return; + } + + List conflicts = new ArrayList<>(); + List users = this.persistenceHandler.getAllUsers(); + for (User user : users) { + Map privilegeNames = new HashMap<>(); + conflicts.addAll(detectPrivilegeConflicts(privilegeNames, user)); + } + + if (!conflicts.isEmpty()) { + for (String conflict : conflicts) { + logger.error(conflict); + } + throw new PrivilegeException("There are " + conflicts.size() + " privilege conflicts!"); + } + } + + private void assertNoPrivilegeConflict(User user) { + if (this.privilegeConflictResolution.isStrict()) { + Map privilegeNames = new HashMap<>(); + List conflicts = detectPrivilegeConflicts(privilegeNames, user); + if (!conflicts.isEmpty()) { + String msg = conflicts.stream().collect(Collectors.joining("\n")); + throw new PrivilegeException(msg); + } + } + } + + private void assertNoPrivilegeConflict(Role role) { + if (!this.privilegeConflictResolution.isStrict()) + return; + + Map privilegeNames = new HashMap<>(); + for (String privilegeName : role.getPrivilegeNames()) { + privilegeNames.put(privilegeName, role.getName()); + } + + List conflicts = new ArrayList<>(); + List users = this.persistenceHandler.getAllUsers(); + for (User user : users) { + if (user.hasRole(role.getName())) + conflicts.addAll(detectPrivilegeConflicts(privilegeNames, user)); + } + + if (!conflicts.isEmpty()) { + String msg = conflicts.stream().collect(Collectors.joining("\n")); + throw new PrivilegeException(msg); + } + } + + private List detectPrivilegeConflicts(Map privilegeNames, User user) { + List conflicts = new ArrayList<>(); + + Set userRoles = user.getRoles(); + for (String roleName : userRoles) { + Role role = this.persistenceHandler.getRole(roleName); + for (String privilegeName : role.getPrivilegeNames()) { + if (!privilegeNames.containsKey(privilegeName)) { + privilegeNames.put(privilegeName, roleName); + } else { + String roleOrigin = privilegeNames.get(privilegeName); + String msg = "User {0} has conflicts for privilege {1} on roles {2} and {3}"; + msg = MessageFormat.format(msg, user.getUsername(), privilegeName, roleOrigin, roleName); + conflicts.add(msg); + } + } + } + + return conflicts; + } + + /** + * Validates that the policies which are not null on the privileges of the role exist + * + * @param role + * the role for which the policies are to be checked + */ + private void validatePolicies(Role role) { + for (String privilegeName : role.getPrivilegeNames()) { + IPrivilege privilege = role.getPrivilege(privilegeName); + String policy = privilege.getPolicy(); + if (policy != null && !this.policyMap.containsKey(policy)) { + String msg = "Policy {0} for Privilege {1} does not exist on role {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, policy, privilege.getName(), role); + throw new PrivilegeException(msg); + } + } + } + + /** + * Passwords should not be kept as strings, as string are immutable, this method thus clears the byte array so that + * the password is not in memory anymore + * + * @param password + * the byte array containing the passwort which is to be set to zeroes + */ + private void clearPassword(byte[] password) { + if (password != null) { + for (int i = 0; i < password.length; i++) { + password[i] = 0; + } + } + } + + @Override + public T runAsSystem(String systemUsername, T action) throws PrivilegeException { + + if (systemUsername == null) + throw new PrivilegeException("systemUsername may not be null!"); //$NON-NLS-1$ + if (action == null) + throw new PrivilegeException("action may not be null!"); //$NON-NLS-1$ + + // get the system user + User systemUser = this.persistenceHandler.getUser(systemUsername); + if (systemUser == null) + throw new PrivilegeException(MessageFormat.format("System user {0} does not exist!", systemUsername)); //$NON-NLS-1$ + + // validate this is a system user + if (systemUser.getUserState() != UserState.SYSTEM) + throw new PrivilegeException(MessageFormat.format("User {0} is not a System user!", systemUsername)); //$NON-NLS-1$ + + // get privilegeContext for this system user + PrivilegeContext systemUserPrivilegeContext = getSystemUserPrivilegeContext(systemUsername); + + // validate this system user may perform the given action + systemUserPrivilegeContext.validateAction(action); + + String sessionId = systemUserPrivilegeContext.getCertificate().getSessionId(); + this.privilegeContextMap.put(sessionId, systemUserPrivilegeContext); + try { + // perform the action + action.execute(systemUserPrivilegeContext); + } finally { + this.privilegeContextMap.remove(sessionId); + } + + return action; + } + + /** + * Returns the {@link Certificate} for the given system username. If it does not yet exist, then it is created by + * authenticating the system user + * + * @param systemUsername + * the name of the system user + * + * @return the {@link Certificate} for this system user + */ + private PrivilegeContext getSystemUserPrivilegeContext(String systemUsername) { + + // get user object + User user = this.persistenceHandler.getUser(systemUsername); + // no user means no authentication + if (user == null) { + String msg = MessageFormat.format("The system user with username {0} does not exist!", systemUsername); //$NON-NLS-1$ + throw new AccessDeniedException(msg); + } + + // validate password + String pwHash = user.getPassword(); + if (pwHash != null) { + String msg = MessageFormat.format("System users must not have a password: {0}", systemUsername); //$NON-NLS-1$ + throw new AccessDeniedException(msg); + } + + // validate user state is system + if (user.getUserState() != UserState.SYSTEM) { + String msg = "The system {0} user does not have expected user state {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, systemUsername, UserState.SYSTEM); + throw new PrivilegeException(msg); + } + + // validate user has at least one role + if (user.getRoles().isEmpty()) { + String msg = MessageFormat.format("The system user {0} does not have any roles defined!", systemUsername); //$NON-NLS-1$ + throw new PrivilegeException(msg); + } + + // get 2 auth tokens + String authToken = this.encryptionHandler.nextToken(); + + // get next session id + String sessionId = UUID.randomUUID().toString(); + + // create a new certificate, with details of the user + Certificate systemUserCertificate = new Certificate(sessionId, systemUsername, user.getFirstname(), + user.getLastname(), user.getUserState(), authToken, new Date(), user.getLocale(), user.getRoles(), + new HashMap<>(user.getProperties())); + systemUserCertificate.setLastAccess(new Date()); + + // create and save a new privilege context + PrivilegeContext privilegeContext = buildPrivilegeContext(systemUserCertificate, user); + + // log + String msg = "The system user ''{0}'' is logged in with session {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, systemUsername, systemUserCertificate.getSessionId()); + DefaultPrivilegeHandler.logger.info(msg); + + return privilegeContext; + } + + /** + *

+ * This method instantiates a {@link PrivilegePolicy} object from the given policyName. The {@link PrivilegePolicy} + * is not stored in a database. The privilege name is a class name and is then used to instantiate a new + * {@link PrivilegePolicy} object + *

+ * + * @param policyName + * the class name of the {@link PrivilegePolicy} object to return + * + * @return the {@link PrivilegePolicy} object + * + * @throws PrivilegeException + * if the {@link PrivilegePolicy} object for the given policy name could not be instantiated + */ + private PrivilegePolicy getPolicy(String policyName) { + + // get the policies class + Class policyClazz = this.policyMap.get(policyName); + if (policyClazz == null) { + return null; + } + + // instantiate the policy + PrivilegePolicy policy; + try { + + policy = policyClazz.newInstance(); + } catch (Exception e) { + String msg = "The class for the policy with the name {0} does not exist!{1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, policyName, policyName); + throw new PrivilegeException(msg, e); + } + + return policy; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/EncryptionHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/EncryptionHandler.java new file mode 100644 index 000000000..238772be8 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/EncryptionHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import java.util.Map; + +/** + * The {@link EncryptionHandler} exposes API which is used to handle encrypting of strings, or returning secure tokens + * for certificates and so forth + * + * @author Robert von Burg + */ +public interface EncryptionHandler { + + /** + * Calculates or generates a token which can be used to identify certificates and so forth + * + * @return the secure token + */ + public String nextToken(); + + /** + * Converts a given string, e.g. a password to a hash which is defined by the concrete implementation + * + * @param string + * the string to convert + * @return the hash of the string after converting + */ + public String convertToHash(String string); + + /** + * Converts a given byte array, e.g. a password to a hash which is defined by the concrete implementation + * + * @param bytes + * the bytes to convert + * @return the hash of the string after converting + */ + public String convertToHash(byte[] bytes); + + /** + * Initialize the concrete {@link EncryptionHandler}. The passed parameter map contains any configuration the + * concrete {@link EncryptionHandler} might need + * + * @param parameterMap + * a map containing configuration properties + */ + public void initialize(Map parameterMap); +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PersistenceHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PersistenceHandler.java new file mode 100644 index 000000000..627f86333 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PersistenceHandler.java @@ -0,0 +1,151 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import java.util.List; +import java.util.Map; + +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; +import li.strolch.privilege.policy.PrivilegePolicy; + +/** + *

+ * The {@link PersistenceHandler} takes care of retrieving and persisting model objects to the underlying database. This + * database can be simple XML files, or an LDAP and so forth + *

+ * + *

+ * The {@link PersistenceHandler} also serves the special {@link PrivilegePolicy} objects. These policies are special + * objects which implement an algorithm to define if an action is allowed on a {@link Restrictable} by a {@link Role} + * and {@link IPrivilege} + *

+ * + * @author Robert von Burg + */ +public interface PersistenceHandler { + + /** + * Returns all currently known {@link User}s + * + * @return all currently known {@link User}s + */ + public List getAllUsers(); + + /** + * Returns all currently known {@link Role}s + * + * @return all currently known {@link Role}s + */ + public List getAllRoles(); + + /** + * Returns a {@link User} object from the underlying database + * + * @param username + * the name/id of the {@link User} object to return + * + * @return the {@link User} object, or null if it was not found + */ + public User getUser(String username); + + /** + * Returns a {@link Role} object from the underlying database + * + * @param roleName + * the name/id of the {@link Role} object to return + * + * @return the {@link Role} object, or null if it was not found + */ + public Role getRole(String roleName); + + /** + * Removes a {@link User} with the given name and returns the removed object if it existed + * + * @param username + * the name of the {@link User} to remove + * + * @return the {@link User} removed, or null if it did not exist + */ + public User removeUser(String username); + + /** + * Removes a {@link Role} with the given name and returns the removed object if it existed + * + * @param roleName + * the name of the {@link Role} to remove + * + * @return the {@link Role} removed, or null if it did not exist + */ + public Role removeRole(String roleName); + + /** + * Adds a {@link User} object to the underlying database + * + * @param user + * the {@link User} object to add + */ + public void addUser(User user); + + /** + * Replaces the existing {@link User} object in the underlying database + * + * @param user + * the {@link User} object to add + */ + public void replaceUser(User user); + + /** + * Adds a {@link Role} object to the underlying database + * + * @param role + * the {@link User} object to add + */ + public void addRole(Role role); + + /** + * Replaces the {@link Role} object in the underlying database + * + * @param role + * the {@link User} object to add + */ + public void replaceRole(Role role); + + /** + * Informs this {@link PersistenceHandler} to persist any changes which need to be saved + * + * @return true if changes were persisted successfully, false if nothing needed to be persisted + */ + public boolean persist(); + + /** + * Informs this {@link PersistenceHandler} to reload the data from the backend + * + * @return true if the reload was successful, false if something went wrong + */ + public boolean reload(); + + /** + * Initialize the concrete {@link PersistenceHandler}. The passed parameter map contains any configuration the + * concrete {@link PersistenceHandler} might need + * + * @param parameterMap + * a map containing configuration properties + */ + public void initialize(Map parameterMap); +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java new file mode 100644 index 000000000..65dcdaf79 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java @@ -0,0 +1,689 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeConflictResolution; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.RoleRep; +import li.strolch.privilege.model.UserRep; +import li.strolch.privilege.model.UserState; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; +import li.strolch.privilege.policy.PrivilegePolicy; + +/** + * The {@link PrivilegeHandler} is the centrally exposed API for accessing the privilege library. It exposes all needed + * methods to access Privilege data model objects, modify them and validate if users or roles have privileges to perform + * an action + * + * @author Robert von Burg + */ +public interface PrivilegeHandler { + + /// + + /** + * Privilege "PrivilegeAction" which is used for privileges which are not further categorized e.g. s + * {@link #PRIVILEGE_ACTION_PERSIST} and {@link #PRIVILEGE_ACTION_GET_POLICIES} + */ + public static final String PRIVILEGE_ACTION = "PrivilegeAction"; + + /** + * For Privilege "PrivilegeAction" value required to be able to persist changes if not exempted by auto persist or + * allAllowed + */ + public static final String PRIVILEGE_ACTION_PERSIST = "Persist"; + /** + * For Privilege "PrivilegeAction" value required to be able to persist session if not exempted by + * allAllowed + */ + public static final String PRIVILEGE_ACTION_PERSIST_SESSIONS = "PersistSessions"; + /** + * For Privilege "PrivilegeAction" value required to be able to reload changes if not exempted by + * allAllowed + */ + public static final String PRIVILEGE_ACTION_RELOAD = "Reload"; + /** + * For Privilege "PrivilegeAction" value required to get currently configured policies if not + * allAllowed + */ + public static final String PRIVILEGE_ACTION_GET_POLICIES = "GetPolicies"; + /** + * For Privilege "PrivilegeAction" value required to get a certificate if not allAllowed + */ + public static final String PRIVILEGE_ACTION_GET_CERTIFICATE = "GetCertificate"; + /** + * For Privilege "PrivilegeAction" value required to get all certificates if not allAllowed + */ + public static final String PRIVILEGE_ACTION_GET_CERTIFICATES = "GetCertificates"; + + /// + + /** + * Privilege "PrivilegeGetRole" which is used to validate that a user can get a specific role + */ + public static final String PRIVILEGE_GET_ROLE = "PrivilegeGetRole"; + /** + * Privilege "PrivilegeAddRole" which is used to validate that a user can add a specific role + */ + public static final String PRIVILEGE_ADD_ROLE = "PrivilegeAddRole"; + /** + * Privilege "PrivilegeRemoveRole" which is used to validate that a user can remove a specific role + */ + public static final String PRIVILEGE_REMOVE_ROLE = "PrivilegeRemoveRole"; + /** + * Privilege "PrivilegeModifyRole" which is used to validate that a user can modify a specific role. Note: + * This includes modifying of the privileges on the role + */ + public static final String PRIVILEGE_MODIFY_ROLE = "PrivilegeModifyRole"; + + /// + + /** + * Privilege "PrivilegeGetUser" which is used to validate that a user can get a specific user + */ + public static final String PRIVILEGE_GET_USER = "PrivilegeGetUser"; + /** + * Privilege "PrivilegeAddUser" which is used to validate that a user can add a specific user + */ + public static final String PRIVILEGE_ADD_USER = "PrivilegeAddUser"; + /** + * Privilege "PrivilegeRemoveUser" which is used to validate that a user can remove a specific user + */ + public static final String PRIVILEGE_REMOVE_USER = "PrivilegeRemoveUser"; + /** + * Privilege "PrivilegeModifyUser" which is used to validate that a user can modify a specific user + */ + public static final String PRIVILEGE_MODIFY_USER = "PrivilegeModifyUser"; + /** + * Privilege "PrivilegeAddRoleToUser" which is used to validate that a user can add a specific role to a specific + * user + */ + public static final String PRIVILEGE_ADD_ROLE_TO_USER = "PrivilegeAddRoleToUser"; + /** + * Privilege "PrivilegeRemoveRoleFromUser" which is used to validate that a user can remove a specific role from a + * specific user + */ + public static final String PRIVILEGE_REMOVE_ROLE_FROM_USER = "PrivilegeRemoveRoleFromUser"; + /** + * Privilege "PRIVILEGE_SET_USER_LOCALE" which is used to validate that a user can set the locale of a user, or + * their own + */ + public static final String PRIVILEGE_SET_USER_LOCALE = "PrivilegeSetUserLocale"; + /** + * Privilege "PRIVILEGE_SET_USER_STATE" which is used to validate that a user can set the state of a user + */ + public static final String PRIVILEGE_SET_USER_STATE = "PrivilegeSetUserState"; + /** + * Privilege "PRIVILEGE_SET_USER_PASSWORD" which is used to validate that a user can set the password of a user, or + * their own + */ + public static final String PRIVILEGE_SET_USER_PASSWORD = "PrivilegeSetUserPassword"; + + /// + + /** + * configuration parameter to define a secret_key + */ + public static final String PARAM_SECRET_KEY = "secretKey"; //$NON-NLS-1$ + + /** + * configuration parameter to define a secret salt + */ + public static final String PARAM_SECRET_SALT = "secretSalt"; //$NON-NLS-1$ + + /** + * configuration parameter to define automatic persisting on password change + */ + public static final String PARAM_AUTO_PERSIST_ON_USER_CHANGES_DATA = "autoPersistOnUserChangesData"; //$NON-NLS-1$ + + /** + * configuration parameter to define if sessions should be persisted + */ + public static final String PARAM_PERSIST_SESSIONS = "persistSessions"; //$NON-NLS-1$ + + /** + * configuration parameter to define where sessions are to be persisted + */ + public static final String PARAM_PERSIST_SESSIONS_PATH = "persistSessionsPath"; //$NON-NLS-1$ + + /** + * configuration parameter to define {@link PrivilegeConflictResolution} + */ + public static final String PARAM_PRIVILEGE_CONFLICT_RESOLUTION = "privilegeConflictResolution"; + + /** + * Returns a {@link UserRep} for the given username + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the name of the {@link UserRep} to return + * + * @return the {@link UserRep} for the given username, or null if it was not found + */ + public UserRep getUser(Certificate certificate, String username); + + /** + * Returns a {@link RoleRep} for the given roleName + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param roleName + * the name of the {@link RoleRep} to return + * + * @return the {@link RoleRep} for the given roleName, or null if it was not found + */ + public RoleRep getRole(Certificate certificate, String roleName); + + /** + * Returns the map of {@link PrivilegePolicy} definitions + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return the map of {@link PrivilegePolicy} definitions + */ + public Map getPolicyDefs(Certificate certificate); + + /** + * Returns the list of {@link Certificate Certificates} + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return the list of {@link Certificate Certificates} + */ + public List getCertificates(Certificate certificate); + + /** + * Returns all {@link RoleRep RoleReps} + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return the list of {@link RoleRep RoleReps} + */ + public List getRoles(Certificate certificate); + + /** + * Returns all {@link UserRep UserReps} + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return the list of {@link UserRep UserReps} + */ + public List getUsers(Certificate certificate); + + /** + * Method to query {@link UserRep} which meet the criteria set in the given {@link UserRep}. Null fields mean the + * fields are irrelevant. + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param selectorRep + * the {@link UserRep} to use as criteria selection + * + * @return a list of {@link UserRep}s which fit the given criteria + */ + public List queryUsers(Certificate certificate, UserRep selectorRep); + + /** + * Removes the user with the given username + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the username of the user to remove + * + * @return the {@link UserRep} of the user removed, or null if the user did not exist + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public UserRep removeUser(Certificate certificate, String username) + throws AccessDeniedException, PrivilegeException; + + /** + * Removes the role with the given roleName from the user with the given username + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the username of the user from which the role is to be removed + * @param roleName + * the roleName of the role to remove from the user + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public UserRep removeRoleFromUser(Certificate certificate, String username, String roleName) + throws AccessDeniedException, PrivilegeException; + + /** + * Removes the role with the given roleName + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param roleName + * the roleName of the role to remove + * + * @return the {@link RoleRep} of the role removed, or null if the role did not exist + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or the role is still in use by a user + */ + public RoleRep removeRole(Certificate certificate, String roleName) + throws AccessDeniedException, PrivilegeException; + + /** + * Removes the privilege with the given privilegeName from the role with the given roleName + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param roleName + * the roleName of the role from which the privilege is to be removed + * @param privilegeName + * the privilegeName of the privilege to remove from the role + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public RoleRep removePrivilegeFromRole(Certificate certificate, String roleName, String privilegeName) + throws AccessDeniedException, PrivilegeException; + + /** + *

+ * Adds a new user with the information from this {@link UserRep} + *

+ * + *

+ * If the password given is null, then the user is created, but can not not login! Otherwise the password must meet + * the requirements of the implementation under {@link PrivilegeHandler#validatePassword(byte[])} + *

+ * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param userRep + * the {@link UserRep} containing the information to create the new {@link User} + * @param password + * the password of the new user. If the password is null, then this is accepted but the user can not + * login, otherwise the password must be validated against + * {@link PrivilegeHandler#validatePassword(byte[])} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or the user already exists + */ + public UserRep addUser(Certificate certificate, UserRep userRep, byte[] password) + throws AccessDeniedException, PrivilegeException; + + /** + *

+ * Updates the fields for the user with the given user. All fields on the given {@link UserRep} which are non-null + * will be updated on the existing user. The username on the given {@link UserRep} must be set and correspond to an + * existing user. + *

+ * + * The following fields are considered updateable: + *
    + *
  • {@link UserRep#getFirstname()}
  • + *
  • {@link UserRep#getLastname()}
  • + *
  • {@link UserRep#getLocale()}
  • + *
  • {@link UserRep#getProperties()} - the existing properties will be replaced with the given properties
  • + *
+ * + *

+ * Any other fields will be ignored + *

+ * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param userRep + * the {@link UserRep} with the fields set to their new values + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or if the user does not exist + */ + public UserRep updateUser(Certificate certificate, UserRep userRep) + throws AccessDeniedException, PrivilegeException; + + /** + *

+ * Replaces the existing user with the information from this {@link UserRep} if the user already exists + *

+ * + *

+ * If the password given is null, then the user is created, but can not not login! Otherwise the password must meet + * the requirements of the implementation under {@link PrivilegeHandler#validatePassword(byte[])} + *

+ * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param userRep + * the {@link UserRep} containing the information to replace the existing {@link User} + * @param password + * the password of the new user. If the password is null, then this is accepted but the user can not + * login, otherwise the password must be validated against + * {@link PrivilegeHandler#validatePassword(byte[])} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or if the user does not exist + */ + public UserRep replaceUser(Certificate certificate, UserRep userRep, byte[] password) + throws AccessDeniedException, PrivilegeException; + + /** + * Adds a new role with the information from this {@link RoleRep} + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param roleRep + * the {@link RoleRep} containing the information to create the new {@link Role} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or if the role already exists + */ + public RoleRep addRole(Certificate certificate, RoleRep roleRep) throws AccessDeniedException, PrivilegeException; + + /** + * Replaces the existing role with the information from this {@link RoleRep} + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param roleRep + * the {@link RoleRep} containing the information to replace the existing {@link Role} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or if the role does not exist + */ + public RoleRep replaceRole(Certificate certificate, RoleRep roleRep) + throws AccessDeniedException, PrivilegeException; + + /** + * Adds the role with the given roleName to the {@link User} with the given username + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the username of the {@link User} to which the role should be added + * @param roleName + * the roleName of the {@link Role} which should be added to the {@link User} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or if the role does not exist + */ + public UserRep addRoleToUser(Certificate certificate, String username, String roleName) + throws AccessDeniedException, PrivilegeException; + + /** + * Adds the {@link PrivilegeRep} to the {@link Role} with the given roleName or replaces it, if it already exists + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param roleName + * the roleName of the {@link Role} to which the privilege should be added + * @param privilegeRep + * the representation of the {@link IPrivilege} which should be added or replaced on the {@link Role} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate or the role does not exist + */ + public RoleRep addOrReplacePrivilegeOnRole(Certificate certificate, String roleName, PrivilegeRep privilegeRep) + throws AccessDeniedException, PrivilegeException; + + /** + *

+ * Changes the password for the {@link User} with the given username. If the password is null, then the {@link User} + * can not login anymore. Otherwise the password must meet the requirements of the implementation under + * {@link PrivilegeHandler#validatePassword(byte[])} + *

+ * + *

+ * It should be possible for a user to change their own password + *

+ * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the username of the {@link User} for which the password is to be changed + * @param password + * the new password for this user. If the password is null, then the {@link User} can not login anymore. + * Otherwise the password must meet the requirements of the implementation under + * {@link PrivilegeHandler#validatePassword(byte[])} + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public void setUserPassword(Certificate certificate, String username, byte[] password) + throws AccessDeniedException, PrivilegeException; + + /** + * Changes the {@link UserState} of the user + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the username of the {@link User} for which the {@link UserState} is to be changed + * @param state + * the new state for the user + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public UserRep setUserState(Certificate certificate, String username, UserState state) + throws AccessDeniedException, PrivilegeException; + + /** + * Changes the {@link Locale} of the user + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * @param username + * the username of the {@link User} for which the {@link Locale} is to be changed + * @param locale + * the new {@link Locale} for the user + * + * @throws AccessDeniedException + * if the user for this certificate may not perform the action + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public UserRep setUserLocale(Certificate certificate, String username, Locale locale) + throws AccessDeniedException, PrivilegeException; + + /** + * Authenticates a user by validating that a {@link User} for the given username and password exist and then returns + * a {@link Certificate} with which this user may then perform actions + * + * @param username + * the username of the {@link User} which is registered in the {@link PersistenceHandler} + * @param password + * the password with which this user is to be authenticated. Null passwords are not accepted and they + * must meet the requirements of the {@link #validatePassword(byte[])}-method + * + * @return a {@link Certificate} with which this user may then perform actions + * + * @throws AccessDeniedException + * if the user credentials are not valid + */ + public Certificate authenticate(String username, byte[] password) throws AccessDeniedException; + + /** + * Invalidates the session for the given {@link Certificate}, effectively logging out the user who was authenticated + * with the credentials associated to the given {@link Certificate} + * + * @param certificate + * the {@link Certificate} for which the session is to be invalidated + * @return true if the session was still valid and is now invalidated, false otherwise + */ + public boolean invalidateSession(Certificate certificate); + + /** + * Checks if the given {@link Certificate} is valid. This means that the certificate is for a valid session and that + * the user exists for the certificate. This method checks if the {@link Certificate} has been tampered with + * + * @param certificate + * the {@link Certificate} to check + * + * @throws PrivilegeException + * if there is anything wrong with this certificate + */ + public void isCertificateValid(Certificate certificate) throws PrivilegeException; + + /** + * Checks that the given password belongs to the given {@link Certificate}. If it doesn't, then a + * {@link PrivilegeException} is thrown + * + * @param certificate + * the certificate for which to check the password + * @param password + * the password to check against the user from the certificate + * + * @throws PrivilegeException + * if the certificate is invalid or the password does not match + */ + public void checkPassword(Certificate certificate, byte[] password) throws PrivilegeException; + + /** + * Returns the {@link PrivilegeContext} for the given {@link Certificate}. The {@link PrivilegeContext} is an + * encapsulated state of a user's privileges so that for the duration of a user's call, the user can perform their + * actions and do not need to access the {@link PrivilegeHandler} anymore + * + * @param certificate + * a valid {@link Certificate} for which a {@link PrivilegeContext} is to be returned + * @return the {@link PrivilegeContext} for the given {@link Certificate} + * + * @throws PrivilegeException + * if there is a configuration error or the {@link Certificate} is invalid + */ + public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException; + + /** + * Validate that the given password meets certain requirements. What these requirements are is a decision made by + * the concrete implementation + * + * @param password + * the password to be validated to meet certain requirements + * + * @throws PrivilegeException + * if the password does not implement the requirement of the concrete implementation + */ + public void validatePassword(byte[] password) throws PrivilegeException; + + /** + *

+ * Informs this {@link PersistenceHandler} to reload the data from the backend + *

+ * + * Note: It depends on the underlying {@link PersistenceHandler} implementation if data really is read + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return true if the reload was successful, false if something went wrong + * + * @throws AccessDeniedException + * if the users of the given certificate does not have the privilege to perform this action + */ + public boolean reload(Certificate certificate); + + /** + * Persists any changes to the privilege data model. Changes are thus not persisted immediately, but must be + * actively performed + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return true if changes were persisted, false if no changes were persisted + * + * @throws AccessDeniedException + * if the users of the given certificate does not have the privilege to perform this action + */ + public boolean persist(Certificate certificate) throws AccessDeniedException; + + /** + * Persists all currently active sessions + * + * @param certificate + * the {@link Certificate} of the user which has the privilege to perform this action + * + * @return true if changes were persisted, false if not (i.e. not enabled) + * + * @throws AccessDeniedException + * if the users of the given certificate does not have the privilege to perform this action + */ + public boolean persistSessions(Certificate certificate) throws AccessDeniedException; + + /** + * Special method to perform work as a System user, meaning the given systemUsername corresponds to an account which + * has the state {@link UserState#SYSTEM} and this user must have privilege to perform the concrete implementation + * of the given {@link SystemUserAction} instance + * + * + * @param systemUsername + * the username of the system user to perform the action as + * @param action + * the action to be performed as the system user + * + * @return the action + * + * @throws PrivilegeException + */ + public T runAsSystem(String systemUsername, T action) throws PrivilegeException; + + /** + * Returns the {@link EncryptionHandler} instance + * + * @return the {@link EncryptionHandler} instance + */ + public EncryptionHandler getEncryptionHandler() throws PrivilegeException; +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/SystemUserAction.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/SystemUserAction.java new file mode 100644 index 000000000..6bb57d15d --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/SystemUserAction.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; + +/** + * With this interface system actions, which are to be performed in an automated fashion, i.e. by cron jobs, can be + * implemented and then the authorized execution can be delegated to + * {@link PrivilegeHandler#runAsSystem(String, SystemUserAction)} + * + * @author Robert von Burg + */ +public abstract class SystemUserAction implements Restrictable { + + @Override + public String getPrivilegeName() { + return SystemUserAction.class.getName(); + } + + @Override + public Object getPrivilegeValue() { + return this.getClass().getName(); + } + + /** + * This method will be called by the {@link PrivilegeHandler} when an authorized {@link Certificate} has been + * generated to allow this action to properly validate its execution + * + * TODO: I'm not really happy with this... we might want to pass the certificate and then force the action to + * validate it to get the {@link PrivilegeContext} - we don't want the {@link PrivilegeContext} to live forever... + * + * @param privilegeContext + * the {@link PrivilegeContext} which was generated for a valid system user + */ + public abstract void execute(PrivilegeContext privilegeContext); +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/XmlPersistenceHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/XmlPersistenceHandler.java new file mode 100644 index 000000000..638b79f58 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/XmlPersistenceHandler.java @@ -0,0 +1,314 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.handler; + +import java.io.File; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; +import li.strolch.privilege.xml.PrivilegeRolesDomWriter; +import li.strolch.privilege.xml.PrivilegeRolesSaxReader; +import li.strolch.privilege.xml.PrivilegeUsersDomWriter; +import li.strolch.privilege.xml.PrivilegeUsersSaxReader; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.helper.XmlHelper; + +/** + * {@link PersistenceHandler} implementation which reads the configuration from XML files. These configuration is passed + * in {@link #initialize(Map)} + * + * @author Robert von Burg + */ +public class XmlPersistenceHandler implements PersistenceHandler { + + protected static final Logger logger = LoggerFactory.getLogger(XmlPersistenceHandler.class); + + private Map userMap; + private Map roleMap; + + private boolean userMapDirty; + private boolean roleMapDirty; + + private Map parameterMap; + + private long usersFileDate; + private long rolesFileDate; + private File usersPath; + private File rolesPath; + + @Override + public List getAllUsers() { + synchronized (this.userMap) { + return new LinkedList<>(this.userMap.values()); + } + } + + @Override + public List getAllRoles() { + synchronized (this.roleMap) { + return new LinkedList<>(this.roleMap.values()); + } + } + + @Override + public User getUser(String username) { + return this.userMap.get(username); + } + + @Override + public Role getRole(String roleName) { + return this.roleMap.get(roleName); + } + + @Override + public User removeUser(String username) { + User user = this.userMap.remove(username); + this.userMapDirty = user != null; + return user; + } + + @Override + public Role removeRole(String roleName) { + Role role = this.roleMap.remove(roleName); + this.roleMapDirty = role != null; + return role; + } + + @Override + public void addUser(User user) { + if (this.userMap.containsKey(user.getUsername())) + throw new IllegalStateException(MessageFormat.format("The user {0} already exists!", user.getUsername())); + this.userMap.put(user.getUsername(), user); + this.userMapDirty = true; + } + + @Override + public void replaceUser(User user) { + if (!this.userMap.containsKey(user.getUsername())) + throw new IllegalStateException(MessageFormat + .format("The user {0} can not be replaced as it does not exiset!", user.getUsername())); + this.userMap.put(user.getUsername(), user); + this.userMapDirty = true; + } + + @Override + public void addRole(Role role) { + if (this.roleMap.containsKey(role.getName())) + throw new IllegalStateException(MessageFormat.format("The role {0} already exists!", role.getName())); + this.roleMap.put(role.getName(), role); + this.roleMapDirty = true; + } + + @Override + public void replaceRole(Role role) { + if (!this.roleMap.containsKey(role.getName())) + throw new IllegalStateException( + MessageFormat.format("The role {0} can not be replaced as it does not exist!", role.getName())); + this.roleMap.put(role.getName(), role); + this.roleMapDirty = true; + } + + /** + * Initializes this {@link XmlPersistenceHandler} by reading the following parameters: + *
    + *
  • {@link XmlConstants#XML_PARAM_BASE_PATH}
  • + *
  • {@link XmlConstants#XML_PARAM_MODEL_FILE}
  • + *
+ */ + @Override + public void initialize(Map paramsMap) { + + // copy parameter map + this.parameterMap = Collections.unmodifiableMap(new HashMap<>(paramsMap)); + + // get and validate base bath + String basePath = this.parameterMap.get(XmlConstants.XML_PARAM_BASE_PATH); + File basePathF = new File(basePath); + if (!basePathF.exists() && !basePathF.isDirectory()) { + String msg = "[{0}] Defined parameter {1} does not point to a valid path at {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_BASE_PATH, + basePathF.getAbsolutePath()); + throw new PrivilegeException(msg); + } + + // get users file name + String usersFileName = this.parameterMap.get(XmlConstants.XML_PARAM_USERS_FILE); + if (StringHelper.isEmpty(usersFileName)) { + String msg = "[{0}] Defined parameter {1} is not valid as it is empty!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_USERS_FILE); + throw new PrivilegeException(msg); + } + + // get roles file name + String rolesFileName = this.parameterMap.get(XmlConstants.XML_PARAM_ROLES_FILE); + if (StringHelper.isEmpty(rolesFileName)) { + String msg = "[{0}] Defined parameter {1} is not valid as it is empty!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_ROLES_FILE); + throw new PrivilegeException(msg); + } + + // validate users file exists + String usersPathS = basePath + "/" + usersFileName; //$NON-NLS-1$ + File usersPath = new File(usersPathS); + if (!usersPath.exists()) { + String msg = "[{0}] Defined parameter {1} is invalid as users file does not exist at path {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_USERS_FILE, + usersPath.getAbsolutePath()); + throw new PrivilegeException(msg); + } + + // validate roles file exists + String rolesPathS = basePath + "/" + rolesFileName; //$NON-NLS-1$ + File rolesPath = new File(rolesPathS); + if (!rolesPath.exists()) { + String msg = "[{0}] Defined parameter {1} is invalid as roles file does not exist at path {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_ROLES_FILE, + rolesPath.getAbsolutePath()); + throw new PrivilegeException(msg); + } + + // save path to model + this.usersPath = usersPath; + this.rolesPath = rolesPath; + + if (reload()) + logger.info("Privilege Data loaded."); //$NON-NLS-1$ + } + + /** + * Reads the XML configuration files which contain the model. Which configuration files are parsed was defined in + * the while calling {@link #initialize(Map)} + * + * @see #initialize(Map) + */ + @Override + public boolean reload() { + + this.roleMap = Collections.synchronizedMap(new HashMap()); + this.userMap = Collections.synchronizedMap(new HashMap()); + + // parse models xml file to XML document + PrivilegeUsersSaxReader usersXmlHandler = new PrivilegeUsersSaxReader(); + XmlHelper.parseDocument(this.usersPath, usersXmlHandler); + + PrivilegeRolesSaxReader rolesXmlHandler = new PrivilegeRolesSaxReader(); + XmlHelper.parseDocument(this.rolesPath, rolesXmlHandler); + + this.usersFileDate = this.usersPath.lastModified(); + this.rolesFileDate = this.rolesPath.lastModified(); + + // ROLES + List roles = rolesXmlHandler.getRoles(); + for (Role role : roles) { + this.roleMap.put(role.getName(), role); + } + + // USERS + List users = usersXmlHandler.getUsers(); + for (User user : users) { + this.userMap.put(user.getUsername(), user); + } + + this.userMapDirty = false; + this.roleMapDirty = false; + + logger.info(MessageFormat.format("Read {0} Users", this.userMap.size())); //$NON-NLS-1$ + logger.info(MessageFormat.format("Read {0} Roles", this.roleMap.size())); //$NON-NLS-1$ + + // validate referenced roles exist + for (User user : users) { + for (String roleName : user.getRoles()) { + + // validate that role exists + if (getRole(roleName) == null) { + String msg = "Role {0} does not exist referenced by user {1}"; + msg = MessageFormat.format(msg, roleName, user.getUsername()); + throw new PrivilegeException(msg); + } + } + } + + return true; + } + + /** + * Writes the model to the XML files. Where the files are written to was defined in the {@link #initialize(Map)} + */ + @Override + public boolean persist() { + + // get users file name + String usersFileName = this.parameterMap.get(XmlConstants.XML_PARAM_USERS_FILE); + if (usersFileName == null || usersFileName.isEmpty()) { + String msg = "[{0}] Defined parameter {1} is invalid"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_USERS_FILE); + throw new PrivilegeException(msg); + } + + // get roles file name + String rolesFileName = this.parameterMap.get(XmlConstants.XML_PARAM_ROLES_FILE); + if (rolesFileName == null || rolesFileName.isEmpty()) { + String msg = "[{0}] Defined parameter {1} is invalid"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_ROLES_FILE); + throw new PrivilegeException(msg); + } + + boolean saved = false; + + // get users file + boolean usersFileUnchanged = this.usersPath.exists() && this.usersPath.lastModified() == this.usersFileDate; + if (usersFileUnchanged && !this.userMapDirty) { + logger.warn("Not persisting of users as current file is unchanged and users data is not dirty"); //$NON-NLS-1$ + } else { + + // delegate writing + PrivilegeUsersDomWriter modelWriter = new PrivilegeUsersDomWriter(getAllUsers(), this.usersPath); + modelWriter.write(); + + this.userMapDirty = false; + saved = true; + } + + // get roles file + boolean rolesFileUnchanged = this.rolesPath.exists() && this.rolesPath.lastModified() == this.rolesFileDate; + if (rolesFileUnchanged && !this.roleMapDirty) { + logger.warn("Not persisting of roles as current file is unchanged and roles data is not dirty"); //$NON-NLS-1$ + } else { + + // delegate writing + PrivilegeRolesDomWriter modelWriter = new PrivilegeRolesDomWriter(getAllRoles(), this.rolesPath); + modelWriter.write(); + + this.roleMapDirty = false; + saved = true; + } + + // reset dirty states + + return saved; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/BootstrapConfigurationHelper.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/BootstrapConfigurationHelper.java new file mode 100644 index 000000000..646129d5a --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/BootstrapConfigurationHelper.java @@ -0,0 +1,105 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.helper; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.internal.PrivilegeContainerModel; +import li.strolch.privilege.xml.PrivilegeConfigDomWriter; + +/** + *

+ * This class is a simple application which can be used to bootstrap a new configuration for the + * {@link PrivilegeHandler} + *

+ * + *

+ * Simple execute the application and it will ask a few questions and then write a new set of configuration files which + * can be used to run the {@link PrivilegeHandler} + *

+ * + *

+ * Note:This class is not yet implemented! + *

+ * + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class BootstrapConfigurationHelper { + + // private static final Logger logger = Loggerdoc.getLogger(BootstrapConfigurationHelper.class); + + private static String path; + + private static String defaultPrivilegeContainerXmlFile = "Privilege.xml"; + + //private static String basePath = ""; + //private static String modelFileName = "PrivilegeUsers.xml"; + //private static String hashAlgorithm = "SHA-256"; + + private static String defaultPersistenceHandler = "li.strolch.privilege.handler.DefaultPersistenceHandler"; + private static String defaultEncryptionHandler = "li.strolch.privilege.handler.DefaultEncryptionHandler"; + + /** + * @param args + * the args from the command line + */ + public static void main(String[] args) { + + // get current directory + BootstrapConfigurationHelper.path = System.getProperty("user.dir") + "/newConfig"; + + // TODO ask user where to save configuration, default is pwd/newConfig/.... + + // see if path already exists + File pathF = new File(BootstrapConfigurationHelper.path); + if (pathF.exists()) { + throw new RuntimeException("Path already exists: " + pathF.getAbsolutePath()); + } + + if (!pathF.mkdirs()) { + throw new RuntimeException("Could not create path " + pathF.getAbsolutePath()); + } + + Map parameterMap = new HashMap<>(); + Map encryptionHandlerParameterMap = new HashMap<>(); + Map persistenceHandlerParameterMap = new HashMap<>(); + + // TODO ask other questions... + parameterMap.put("autoPersistOnPasswordChange", "true"); + encryptionHandlerParameterMap.put("hashAlgorithm", "SHA-256"); + persistenceHandlerParameterMap.put("basePath", "./target/test"); + persistenceHandlerParameterMap.put("modelXmlFile", "PrivilegeModel.xml"); + + PrivilegeContainerModel containerModel = new PrivilegeContainerModel(); + containerModel.setParameterMap(parameterMap); + containerModel.setEncryptionHandlerClassName(defaultEncryptionHandler); + containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap); + containerModel.setPersistenceHandlerClassName(defaultPersistenceHandler); + containerModel.setPersistenceHandlerParameterMap(persistenceHandlerParameterMap); + + containerModel.addPolicy("DefaultPrivilege", "li.strolch.privilege.policy.DefaultPrivilege"); + + // now perform work: + File configFile = new File(BootstrapConfigurationHelper.path + "/" + + BootstrapConfigurationHelper.defaultPrivilegeContainerXmlFile); + PrivilegeConfigDomWriter configSaxWriter = new PrivilegeConfigDomWriter(containerModel, configFile); + configSaxWriter.write(); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PasswordCreaterUI.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PasswordCreaterUI.java new file mode 100644 index 000000000..40e68f95d --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PasswordCreaterUI.java @@ -0,0 +1,123 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.helper; + +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.SwingConstants; + +import li.strolch.utils.helper.StringHelper; + +/** + * Simple Swing UI to create passwords + * + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class PasswordCreaterUI { + + /** + * Launches the UI + * + * @param args + * not used + */ + public static void main(String[] args) { + + JFrame.setDefaultLookAndFeelDecorated(true); + + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setTitle("Password creator"); + frame.setLayout(new GridLayout(4, 2)); + + JLabel digest = new JLabel("Digest:", SwingConstants.RIGHT); + JLabel password = new JLabel("Password:", SwingConstants.RIGHT); + JLabel hash = new JLabel("Hash:", SwingConstants.RIGHT); + + String[] digests = new String[] { "MD2", "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512" }; + final JComboBox digestCombo = new JComboBox<>(digests); + digestCombo.setSelectedIndex(3); + final JPasswordField passwordField = new JPasswordField(); + final JTextField hashField = new JTextField(150); + + JButton digestBtn = new JButton("Digest"); + + passwordField.addKeyListener(new KeyListener() { + + @Override + public void keyTyped(KeyEvent e) { + // + } + + @Override + public void keyReleased(KeyEvent e) { + // + } + + @Override + public void keyPressed(KeyEvent e) { + hashField.setText(""); + } + }); + digestBtn.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + try { + String digest = (String) digestCombo.getSelectedItem(); + char[] passwordChar = passwordField.getPassword(); + String password = new String(passwordChar); + String hash = StringHelper.hashAsHex(digest, password); + hashField.setText(hash); + } catch (Exception e1) { + e1.printStackTrace(); + hashField.setText("Failed: " + e1.getLocalizedMessage()); + } + } + }); + + frame.add(digest); + frame.add(digestCombo); + frame.add(password); + frame.add(passwordField); + frame.add(hash); + frame.add(hashField); + frame.add(new JLabel()); + frame.add(digestBtn); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int width = 500; + int height = 160; + frame.setSize(width, height); + frame.setLocation(screenSize.width / 2 - width, screenSize.height / 2 - height); + + frame.setVisible(true); + } +} \ No newline at end of file diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PasswordCreator.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PasswordCreator.java new file mode 100644 index 000000000..2898e12e8 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PasswordCreator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.helper; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.security.MessageDigest; + +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * Simple main class which can be used to create a hash from a password which the user must type in at the command line + *

+ * + *

+ * TODO: Note: currently the password input is echoed which is a security risk + *

+ * + * @author Robert von Burg + */ +public class PasswordCreator { + + /** + * @param args + * the args from the command line, NOT USED + * @throws Exception + * thrown if anything goes wrong + */ + @SuppressWarnings("nls") + public static void main(String[] args) throws Exception { + + BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); + + String hashAlgorithm = null; + while (hashAlgorithm == null) { + System.out.print("Hash Algorithm [SHA-256]: "); + String readLine = r.readLine().trim(); + + if (readLine.isEmpty()) { + hashAlgorithm = "SHA-256"; + } else { + + try { + MessageDigest.getInstance(readLine); + hashAlgorithm = readLine; + } catch (Exception e) { + System.out.println(e.getLocalizedMessage()); + hashAlgorithm = null; + } + } + } + + System.out.print("Password: "); + String password = r.readLine().trim(); + System.out.print("Hash is: " + StringHelper.hashAsHex(hashAlgorithm, password)); + } + +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PrivilegeInitializationHelper.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PrivilegeInitializationHelper.java new file mode 100644 index 000000000..2676b5069 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/PrivilegeInitializationHelper.java @@ -0,0 +1,140 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.helper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.Map; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.DefaultPrivilegeHandler; +import li.strolch.privilege.handler.EncryptionHandler; +import li.strolch.privilege.handler.PersistenceHandler; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.internal.PrivilegeContainerModel; +import li.strolch.privilege.policy.PrivilegePolicy; +import li.strolch.privilege.xml.PrivilegeConfigSaxReader; +import li.strolch.utils.helper.ClassHelper; +import li.strolch.utils.helper.XmlHelper; + +/** + * This class implements the initializing of the {@link PrivilegeHandler} by loading an XML file containing the + * configuration + * + * @author Robert von Burg + */ +public class PrivilegeInitializationHelper { + + /** + * Initializes the {@link DefaultPrivilegeHandler} from the configuration file + * + * @param privilegeXmlFile + * a {@link File} reference to the XML file containing the configuration for Privilege + * + * @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and + * {@link PersistenceHandler} are set and initialized as well + */ + public static PrivilegeHandler initializeFromXml(File privilegeXmlFile) { + + // make sure file exists + if (!privilegeXmlFile.exists()) { + String msg = "Privilege file does not exist at path {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeXmlFile.getAbsolutePath()); + throw new PrivilegeException(msg); + } + + // delegate using input stream + try (FileInputStream fin = new FileInputStream(privilegeXmlFile)) { + return initializeFromXml(fin); + } catch (Exception e) { + String msg = "Failed to load configuration from {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeXmlFile.getAbsolutePath()); + throw new PrivilegeException(msg, e); + } + } + + /** + * Initializes the {@link PrivilegeHandler} by loading from the given input stream. This stream must be a valid XML + * source + * + * @param privilegeConfigInputStream + * the XML stream containing the privilege configuration + * + * @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and + * {@link PersistenceHandler} are set and initialized as well + */ + public static PrivilegeHandler initializeFromXml(InputStream privilegeConfigInputStream) { + + // parse configuration file + PrivilegeContainerModel containerModel = new PrivilegeContainerModel(); + PrivilegeConfigSaxReader xmlHandler = new PrivilegeConfigSaxReader(containerModel); + XmlHelper.parseDocument(privilegeConfigInputStream, xmlHandler); + + return initializeFromXml(containerModel); + } + + /** + * Initializes the {@link PrivilegeHandler} by initializing from the given {@link PrivilegeContainerModel} + * + * @param containerModel + * the configuration for the {@link PrivilegeHandler} + * + * @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and + * {@link PersistenceHandler} are set and initialized as well + */ + public static PrivilegeHandler initializeFromXml(PrivilegeContainerModel containerModel) { + + // initialize encryption handler + String encryptionHandlerClassName = containerModel.getEncryptionHandlerClassName(); + EncryptionHandler encryptionHandler = ClassHelper.instantiateClass(encryptionHandlerClassName); + Map parameterMap = containerModel.getEncryptionHandlerParameterMap(); + try { + encryptionHandler.initialize(parameterMap); + } catch (Exception e) { + String msg = "EncryptionHandler {0} could not be initialized"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, encryptionHandlerClassName); + throw new PrivilegeException(msg, e); + } + + // initialize persistence handler + String persistenceHandlerClassName = containerModel.getPersistenceHandlerClassName(); + PersistenceHandler persistenceHandler = ClassHelper.instantiateClass(persistenceHandlerClassName); + parameterMap = containerModel.getPersistenceHandlerParameterMap(); + try { + persistenceHandler.initialize(parameterMap); + } catch (Exception e) { + String msg = "PersistenceHandler {0} could not be initialized"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, persistenceHandlerClassName); + throw new PrivilegeException(msg, e); + } + + // initialize privilege handler + DefaultPrivilegeHandler privilegeHandler = new DefaultPrivilegeHandler(); + parameterMap = containerModel.getParameterMap(); + Map> policyMap = containerModel.getPolicies(); + try { + privilegeHandler.initialize(parameterMap, encryptionHandler, persistenceHandler, policyMap); + } catch (Exception e) { + String msg = "PrivilegeHandler {0} could not be initialized"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeHandler.getClass().getName()); + throw new PrivilegeException(msg, e); + } + + return privilegeHandler; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/XmlConstants.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/XmlConstants.java new file mode 100644 index 000000000..8c29f4710 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/helper/XmlConstants.java @@ -0,0 +1,245 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.helper; + +/** + * The constants used in parsing XML documents which contain the configuration for Privilege + * + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class XmlConstants { + + /** + * XML_ROOT_PRIVILEGE_CONTAINER = "PrivilegeContainer" : + */ + public static final String XML_ROOT_PRIVILEGE = "Privilege"; + + /** + * XML_CONTAINER = "Container" : + */ + public static final String XML_CONTAINER = "Container"; + + /** + * XML_POLICIES = "Policies" : + */ + public static final String XML_POLICIES = "Policies"; + + /** + * XML_PRIVILEGES = "Privileges" : + */ + public static final String XML_PRIVILEGES = "Privileges"; + + /** + * XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles" : + */ + public static final String XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles"; + + /** + * XML_ROOT_CERTIFICATES = "Certificates" : + */ + public static final String XML_ROOT_CERTIFICATES = "Certificates"; + + /** + * XML_HANDLER_PERSISTENCE = "PersistenceHandler" : + */ + public static final String XML_HANDLER_PERSISTENCE = "PersistenceHandler"; + + /** + * XML_HANDLER_ENCRYPTION = "EncryptionHandler" : + */ + public static final String XML_HANDLER_ENCRYPTION = "EncryptionHandler"; + + /** + * XML_HANDLER_PRIVILEGE = "PrivilegeHandler" : + */ + public static final String XML_HANDLER_PRIVILEGE = "PrivilegeHandler"; + + /** + * XML_ROLES = "Roles" : + */ + public static final String XML_ROLES = "Roles"; + + /** + * XML_ROLE = "Role" : + */ + public static final String XML_ROLE = "Role"; + + /** + * XML_USERS = "Users" : + */ + public static final String XML_USERS = "Users"; + + /** + * XML_CERTIFICATE = "Certificate" : + */ + public static final String XML_CERTIFICATE = "Certificate"; + + /** + * XML_SESSION_DATA = "SessionData" : + */ + public static final String XML_SESSION_DATA = "SessionData"; + + /** + * XML_USER = "User" + */ + public static final String XML_USER = "User"; + + /** + * XML_PRIVILEGE = "Privilege" : + */ + public static final String XML_PRIVILEGE = "Privilege"; + + /** + * XML_POLICY = "Policy" : + */ + public static final String XML_POLICY = "Policy"; + + /** + * XML_PARAMETERS = "Parameters" : + */ + public static final String XML_PARAMETERS = "Parameters"; + + /** + * XML_PARAMETER = "Parameter" : + */ + public static final String XML_PARAMETER = "Parameter"; + + /** + * XML_PROPERTIES = "Properties" : + */ + public static final String XML_PROPERTIES = "Properties"; + + /** + * XML_PROPERTY = "Property" : + */ + public static final String XML_PROPERTY = "Property"; + + /** + * XML_ALL_ALLOWED = "AllAllowed" : + */ + public static final String XML_ALL_ALLOWED = "AllAllowed"; + + /** + * XML_DENY = "Deny" : + */ + public static final String XML_DENY = "Deny"; + + /** + * XML_ALLOW = "Allow" : + */ + public static final String XML_ALLOW = "Allow"; + + /** + * XML_FIRSTNAME = "Firstname" : + */ + public static final String XML_FIRSTNAME = "Firstname"; + + /** + * XML_LASTNAME = "Lastname" : + */ + public static final String XML_LASTNAME = "Lastname"; + + /** + * XML_STATE = "State" : + */ + public static final String XML_STATE = "State"; + + /** + * XML_LOCALE = "Locale" : + */ + public static final String XML_LOCALE = "Locale"; + + /** + * XML_ATTR_CLASS = "class" : + */ + public static final String XML_ATTR_CLASS = "class"; + + /** + * XML_ATTR_LOGIN_TIME = "loginTime" : + */ + public static final String XML_ATTR_LOGIN_TIME = "loginTime"; + + /** + * XML_ATTR_LAST_ACCESS = "lastAccess" : + */ + public static final String XML_ATTR_LAST_ACCESS = "lastAccess"; + + /** + * XML_ATTR_NAME = "name" : + */ + public static final String XML_ATTR_NAME = "name"; + + /** + * XML_ATTR_VALUE = "value" : + */ + public static final String XML_ATTR_VALUE = "value"; + + /** + * XML_ATTR_POLICY = "policy" : + */ + public static final String XML_ATTR_POLICY = "policy"; + + /** + * XML_ATTR_USER_ID = "userId" : + */ + public static final String XML_ATTR_USER_ID = "userId"; + + /** + * XML_ATTR_SESSION_ID = "sessionId" : + */ + public static final String XML_ATTR_SESSION_ID = "sessionId"; + + /** + * XML_ATTR_USERNAME = "username" : + */ + public static final String XML_ATTR_USERNAME = "username"; + + /** + * XML_ATTR_AUTH_TOKEN = "authToken" : + */ + public static final String XML_ATTR_AUTH_TOKEN = "authToken"; + + /** + * XML_ATTR_LOCALE = "locale" : + */ + public static final String XML_ATTR_LOCALE = "locale"; + + /** + * XML_ATTR_PASSWORD = "password" : + */ + public static final String XML_ATTR_PASSWORD = "password"; + + /** + * XML_PARAM_HASH_ALGORITHM = "hashAlgorithm" : + */ + public static final String XML_PARAM_HASH_ALGORITHM = "hashAlgorithm"; + + /** + * XML_PARAM_USERS_FILE = "usersXmlFile" : + */ + public static final String XML_PARAM_USERS_FILE = "usersXmlFile"; + + /** + * XML_PARAM_ROLES_FILE = "rolesXmlFile" : + */ + public static final String XML_PARAM_ROLES_FILE = "rolesXmlFile"; + + /** + * XML_PARAM_BASE_PATH = "basePath" : + */ + public static final String XML_PARAM_BASE_PATH = "basePath"; +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/i18n/PrivilegeMessages.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/i18n/PrivilegeMessages.java new file mode 100644 index 000000000..f8de8c881 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/i18n/PrivilegeMessages.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.i18n; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * @author Robert von Burg + * + */ +public class PrivilegeMessages { + private static final String BUNDLE_NAME = "PrivilegeMessages"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); + + private PrivilegeMessages() { + } + + public static String getString(String key) { + try { + return RESOURCE_BUNDLE.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/Certificate.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/Certificate.java new file mode 100644 index 000000000..fb95ae4fb --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/Certificate.java @@ -0,0 +1,316 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.internal.User; +import li.strolch.utils.helper.StringHelper; + +/** + * The {@link Certificate} is the object a client keeps when accessing a Privilege enabled system. This object is the + * instance which is always used when performing an access and is returned when a user performs a login through + * {@link PrivilegeHandler#authenticate(String, byte[])} + * + * @author Robert von Burg + */ +public final class Certificate implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String sessionId; + private final String username; + private final String firstname; + private final String lastname; + private final UserState userState; + private final String authToken; + private final Date loginTime; + + private final Set userRoles; + private final Map propertyMap; + + private Locale locale; + private Date lastAccess; + + /** + * Default constructor initializing with all information needed for this certificate + * + *

+ * Note, both the authentication token and password are private fields which are generated on login and only known + * by the {@link PrivilegeHandler} + *

+ * + * @param sessionId + * the users session id + * @param username + * the users login name + * @param firstname + * the users first name + * @param lastname + * the users last name + * @param authToken + * the authentication token defining the users unique session and is a private field of this certificate. + * @param locale + * the users {@link Locale} + * @param userRoles + * the user's roles + * @param propertyMap + * a {@link Map} containing string value pairs of properties for the logged in user. These properties can + * be edited and can be used for the user to change settings of this session + */ + public Certificate(String sessionId, String username, String firstname, String lastname, UserState userState, + String authToken, Date loginTime, Locale locale, Set userRoles, Map propertyMap) { + + // validate arguments are not null + if (StringHelper.isEmpty(sessionId)) { + throw new PrivilegeException("sessionId is null!"); //$NON-NLS-1$ + } + if (StringHelper.isEmpty(username)) { + throw new PrivilegeException("username is null!"); //$NON-NLS-1$ + } + if (StringHelper.isEmpty(authToken)) { + throw new PrivilegeException("authToken is null!"); //$NON-NLS-1$ + } + if (userState == null) { + throw new PrivilegeException("userState is null!"); //$NON-NLS-1$ + } + + this.sessionId = sessionId; + this.username = username; + this.firstname = firstname; + this.lastname = lastname; + this.userState = userState; + this.authToken = authToken; + this.loginTime = loginTime; + + // if no locale is given, set default + if (locale == null) + this.locale = Locale.getDefault(); + else + this.locale = locale; + + if (propertyMap == null) + this.propertyMap = Collections.emptyMap(); + else + this.propertyMap = Collections.unmodifiableMap(propertyMap); + + this.userRoles = Collections.unmodifiableSet(userRoles); + } + + /** + * Returns the set or roles this user has + * + * @return the user's roles + */ + public Set getUserRoles() { + return this.userRoles; + } + + /** + * Returns true if the user of this certificate has the given role + * + * @param role + * the role to check for + * + * @return true if the user of this certificate has the given role + */ + public boolean hasRole(String role) { + return this.userRoles.contains(role); + } + + /** + * Returns the {@link User User's} property map. The map is immutable + * + * @return the propertyMap + */ + public Map getPropertyMap() { + return this.propertyMap; + } + + /** + * Returns the property with the given key + * + * @param key + * the key for which the property is to be returned + * + * @return the value of the property with the given key, or null if it does not exist + */ + public String getProperty(String key) { + return this.propertyMap.get(key); + } + + /** + * @return the locale + */ + public Locale getLocale() { + return this.locale; + } + + /** + * @param locale + * the locale to set + */ + public void setLocale(Locale locale) { + this.locale = locale; + } + + /** + * @return the sessionId + */ + public String getSessionId() { + return this.sessionId; + } + + /** + * @return the username + */ + public String getUsername() { + return this.username; + } + + /** + * @return the firstname + */ + public String getFirstname() { + return this.firstname; + } + + /** + * @return the lastname + */ + public String getLastname() { + return this.lastname; + } + + /** + * @return the userState + */ + public UserState getUserState() { + return userState; + } + + /** + * @return the loginTime + */ + public Date getLoginTime() { + return this.loginTime; + } + + /** + * Returns the authToken if the given authPassword is correct, null otherwise + * + * @return the authToken if the given authPassword is correct, null otherwise + */ + public String getAuthToken() { + return this.authToken; + } + + /** + * @return the lastAccess + */ + public Date getLastAccess() { + return this.lastAccess; + } + + /** + * @param lastAccess + * the lastAccess to set + */ + public void setLastAccess(Date lastAccess) { + this.lastAccess = lastAccess; + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Certificate [sessionId="); + builder.append(this.sessionId); + builder.append(", username="); + builder.append(this.username); + + if (StringHelper.isNotEmpty(this.firstname)) { + builder.append(", firstname="); + builder.append(this.firstname); + } + + if (StringHelper.isNotEmpty(this.lastname)) { + builder.append(", lastname="); + builder.append(this.lastname); + } + + builder.append(", locale="); + builder.append(this.locale); + + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.authToken == null) ? 0 : this.authToken.hashCode()); + result = prime * result + ((this.locale == null) ? 0 : this.locale.hashCode()); + result = prime * result + ((this.sessionId == null) ? 0 : this.sessionId.hashCode()); + result = prime * result + ((this.username == null) ? 0 : this.username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof Certificate)) + return false; + Certificate other = (Certificate) obj; + if (this.authToken == null) { + if (other.authToken != null) + return false; + } else if (!this.authToken.equals(other.authToken)) + return false; + if (this.locale == null) { + if (other.locale != null) + return false; + } else if (!this.locale.equals(other.locale)) + return false; + if (this.sessionId == null) { + if (other.sessionId != null) + return false; + } else if (!this.sessionId.equals(other.sessionId)) + return false; + if (this.username == null) { + if (other.username != null) + return false; + } else if (!this.username.equals(other.username)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/IPrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/IPrivilege.java new file mode 100644 index 000000000..958911e4d --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/IPrivilege.java @@ -0,0 +1,86 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import java.util.Set; + +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.policy.PrivilegePolicy; + +/** + *

+ * {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it + * which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a + * {@link PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow + * lists configured which is used to evaluate if privilege is granted to a {@link Restrictable} + *

+ * + * @author Robert von Burg + * + */ +public interface IPrivilege { + + /** + * @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients + */ + public abstract PrivilegeRep asPrivilegeRep(); + + /** + * @return the name + */ + public abstract String getName(); + + /** + * @return the policy + */ + public abstract String getPolicy(); + + /** + * @return the allAllowed + */ + public abstract boolean isAllAllowed(); + + /** + * @return the allowList + */ + public abstract Set getAllowList(); + + /** + * @return the denyList + */ + public abstract Set getDenyList(); + + /** + * @return true if there are values in the allow list + */ + public abstract boolean hasAllowed(); + + /** + * @return if the value is in the allow list + */ + public abstract boolean isAllowed(String value); + + /** + * @return true if there are values in the deny list + */ + public abstract boolean hasDenied(); + + /** + * @return true if the value is in the deny list + */ + public abstract boolean isDenied(String value); + +} \ No newline at end of file diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/PrivilegeContext.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/PrivilegeContext.java new file mode 100644 index 000000000..41d12d969 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/PrivilegeContext.java @@ -0,0 +1,131 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.policy.PrivilegePolicy; + +/** + * This context gives access to a logged in user's privilege data e.g. the {@link UserRep}, {@link Certificate} and the + * user's list of {@link PrivilegeRep} + * + *

+ * Note: This is an internal object which is not to be serialized to clients + *

+ * + * @author Robert von Burg + */ +public class PrivilegeContext { + + // + // object state + // + + private UserRep userRep; + private Certificate certificate; + private Map privileges; + private Map policies; + + public PrivilegeContext(UserRep userRep, Certificate certificate, Map privileges, + Map policies) { + this.userRep = userRep; + this.certificate = certificate; + this.privileges = Collections.unmodifiableMap(new HashMap<>(privileges)); + this.policies = Collections.unmodifiableMap(new HashMap<>(policies)); + } + + public UserRep getUserRep() { + return this.userRep; + } + + public Certificate getCertificate() { + return this.certificate; + } + + public String getUsername() { + return this.userRep.getUsername(); + } + + public Set getPrivilegeNames() { + return this.privileges.keySet(); + } + + public void assertHasPrivilege(String privilegeName) { + if (!this.privileges.containsKey(privilegeName)) { + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), //$NON-NLS-1$ + userRep.getUsername(), privilegeName); + throw new AccessDeniedException(msg); + } + } + + public IPrivilege getPrivilege(String privilegeName) { + assertHasPrivilege(privilegeName); + return this.privileges.get(privilegeName); + } + + public PrivilegePolicy getPolicy(String policyName) { + PrivilegePolicy policy = this.policies.get(policyName); + if (policy == null) { + String msg = "The PrivilegePolicy {0} does not exist on the PrivilegeContext!"; //$NON-NLS-1$ + throw new PrivilegeException(MessageFormat.format(msg, policyName)); + } + return policy; + } + + // + // business logic + // + + /** + * Validates if the user for this context has the privilege to access to the given {@link Restrictable}. If the user + * has the privilege, then this method returns with no exception and void, if the user does not have the privilege, + * then a {@link AccessDeniedException} is thrown. + * + * @param restrictable + * the {@link Restrictable} which the user wants to access + * + * @throws AccessDeniedException + * if the user does not have access + * @throws PrivilegeException + * if there is an internal error due to wrongly configured privileges or programming errors + */ + public void validateAction(Restrictable restrictable) throws AccessDeniedException, PrivilegeException { + + // the privilege for the restrictable + String privilegeName = restrictable.getPrivilegeName(); + IPrivilege privilege = this.privileges.get(privilegeName); + if (privilege == null) { + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), //$NON-NLS-1$ + getUsername(), privilegeName, restrictable.getClass().getName()); + throw new AccessDeniedException(msg); + } + + // get the policy referenced by the restrictable + String policyName = privilege.getPolicy(); + PrivilegePolicy policy = getPolicy(policyName); + + // delegate to the policy + policy.validateAction(this, privilege, restrictable); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/PrivilegeRep.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/PrivilegeRep.java new file mode 100644 index 000000000..ac27dfb96 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/PrivilegeRep.java @@ -0,0 +1,236 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.policy.PrivilegePolicy; +import li.strolch.utils.helper.StringHelper; + +/** + * To keep certain details of the {@link IPrivilege} itself hidden from remote clients and make sure instances are only + * edited by users with the correct privilege, this representational version is allowed to be viewed by remote clients + * and simply wraps all public data from the {@link IPrivilege} + * + * @author Robert von Burg + */ +@XmlRootElement(name = "Privilege") +@XmlAccessorType(XmlAccessType.NONE) +public class PrivilegeRep implements Serializable { + + private static final long serialVersionUID = 1L; + + @XmlAttribute(name = "name") + private String name; + + @XmlAttribute(name = "policy") + private String policy; + + @XmlAttribute(name = "allAllowed") + private boolean allAllowed; + + @XmlElement(name = "denyList") + private Set denyList; + + @XmlElement(name = "allowList") + private Set allowList; + + /** + * Default constructor + * + * @param name + * the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler} + * @param policy + * the {@link PrivilegePolicy} configured to evaluate if the privilege is granted + * @param allAllowed + * a boolean defining if a {@link Role} with this {@link IPrivilege} has unrestricted access to a + * {@link Restrictable} + * @param denyList + * a list of deny rules for this {@link IPrivilege} + * @param allowList + * a list of allow rules for this {@link IPrivilege} + */ + public PrivilegeRep(String name, String policy, boolean allAllowed, Set denyList, Set allowList) { + this.name = name; + this.policy = policy; + this.allAllowed = allAllowed; + this.denyList = denyList; + this.allowList = allowList; + } + + /** + * + */ + @SuppressWarnings("unused") + private PrivilegeRep() { + // no-arg constructor for JAXB + } + + /** + * Validates that all required fields are set + */ + public void validate() { + + if (StringHelper.isEmpty(this.name)) { + throw new PrivilegeException("No name defined!"); //$NON-NLS-1$ + } + + if (StringHelper.isEmpty(this.policy)) { + throw new PrivilegeException("policy is null!"); //$NON-NLS-1$ + } + + if (this.denyList == null) { + throw new PrivilegeException("denyList is null"); //$NON-NLS-1$ + } + if (this.allowList == null) { + throw new PrivilegeException("allowList is null"); //$NON-NLS-1$ + } + } + + /** + * @return the name + */ + public String getName() { + return this.name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the policy + */ + public String getPolicy() { + return this.policy; + } + + /** + * @param policy + * the policy to set + */ + public void setPolicy(String policy) { + this.policy = policy; + } + + /** + * @return the allAllowed + */ + public boolean isAllAllowed() { + return this.allAllowed; + } + + /** + * @param allAllowed + * the allAllowed to set + */ + public void setAllAllowed(boolean allAllowed) { + this.allAllowed = allAllowed; + } + + /** + * @return the denyList + */ + public Set getDenyList() { + return this.denyList == null ? new HashSet<>() : this.denyList; + } + + /** + * @param denyList + * the denyList to set + */ + public void setDenyList(Set denyList) { + this.denyList = denyList; + } + + /** + * @return the allowList + */ + public Set getAllowList() { + return this.allowList == null ? new HashSet<>() : this.allowList; + } + + /** + * @param allowList + * the allowList to set + */ + public void setAllowList(Set allowList) { + this.allowList = allowList; + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PrivilegeRep [name="); + builder.append(this.name); + builder.append(", policy="); + builder.append(this.policy); + builder.append(", allAllowed="); + builder.append(this.allAllowed); + builder.append(", denyList="); + builder.append((this.denyList == null ? "null" : this.denyList.size())); + builder.append(", allowList="); + builder.append((this.allowList == null ? "null" : this.allowList.size())); + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PrivilegeRep other = (PrivilegeRep) obj; + if (this.name == null) { + if (other.name != null) + return false; + } else if (!this.name.equals(other.name)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/Restrictable.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/Restrictable.java new file mode 100644 index 000000000..17e8a401a --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/Restrictable.java @@ -0,0 +1,46 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import li.strolch.privilege.policy.PrivilegePolicy; + +/** + *

+ * Objects implementing this interface are used to grant/restrict privileges to them. A {@link PrivilegePolicy} + * implements the logic on granting/restricting privileges for a {@link Restrictable} and the + * {@link #getPrivilegeName()} is used to find the {@link IPrivilege} which has the associated {@link PrivilegePolicy} + * for evaluating access + *

+ * + * @author Robert von Burg + * + */ +public interface Restrictable { + + /** + * Returns the name of the {@link IPrivilege} which is to be used to validate privileges against + * + * @return the name of the {@link IPrivilege} which is to be used to validate privileges against + */ + public String getPrivilegeName(); + + /** + * Returns the value which defines or describes what privilege is to be granted + * + * @return the value which defines or describes what privilege is to be granted + */ + public Object getPrivilegeValue(); +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/RoleRep.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/RoleRep.java new file mode 100644 index 000000000..fc86b3792 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/RoleRep.java @@ -0,0 +1,168 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.internal.Role; +import li.strolch.utils.helper.StringHelper; + +/** + * To keep certain details of the {@link Role} itself hidden from remote clients and make sure instances are only edited + * by users with the correct privilege, this representational version is allowed to be viewed by remote clients and + * simply wraps all public data from the {@link Role} + * + * @author Robert von Burg + */ +@XmlRootElement(name = "Role") +@XmlAccessorType(XmlAccessType.NONE) +public class RoleRep implements Serializable { + + private static final long serialVersionUID = 1L; + + @XmlAttribute(name = "name") + private String name; + + @XmlElement(name = "privileges") + private List privileges; + + /** + * Default constructor + * + * @param name + * the name of this role + * @param privileges + * the list of privileges granted to this role + */ + public RoleRep(String name, List privileges) { + this.name = name; + this.privileges = privileges; + } + + /** + * + */ + @SuppressWarnings("unused") + private RoleRep() { + // no-arg constructor for JAXB + } + + /** + * validates that all required fields are set + */ + public void validate() { + if (StringHelper.isEmpty(this.name)) + throw new PrivilegeException("name is null"); //$NON-NLS-1$ + + if (this.privileges != null && !this.privileges.isEmpty()) { + for (PrivilegeRep privilege : this.privileges) { + try { + privilege.validate(); + } catch (Exception e) { + String msg = "Privilege {0} is invalid on role {1}"; + msg = MessageFormat.format(msg, privilege.getName(), this.name); + throw new PrivilegeException(msg, e); + } + } + } + } + + /** + * @return the name + */ + public String getName() { + return this.name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the privileges assigned to this Role as a list + * + * @return the privileges assigned to this Role as a list + */ + public List getPrivileges() { + return this.privileges == null ? new ArrayList<>() : this.privileges; + } + + /** + * Sets the privileges on this from a list + * + * @param privileges + * the list of privileges to assign to this role + */ + public void setPrivileges(List privileges) { + this.privileges = privileges; + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("RoleRep [name="); + builder.append(this.name); + builder.append(", privilegeMap="); + builder.append((this.privileges == null ? "null" : this.privileges)); + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RoleRep other = (RoleRep) obj; + if (this.name == null) { + if (other.name != null) + return false; + } else if (!this.name.equals(other.name)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/SimpleRestrictable.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/SimpleRestrictable.java new file mode 100644 index 000000000..f33cea360 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/SimpleRestrictable.java @@ -0,0 +1,45 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import li.strolch.utils.dbc.DBC; + +public class SimpleRestrictable implements Restrictable { + + private final String name; + private final Object value; + + /** + * @param name + * @param value + */ + public SimpleRestrictable(String name, Object value) { + DBC.PRE.assertNotEmpty("name must not be emepty", name); + DBC.PRE.assertNotNull("value must not be null", value); + this.name = name; + this.value = value; + } + + @Override + public String getPrivilegeName() { + return this.name; + } + + @Override + public Object getPrivilegeValue() { + return this.value; + } +} \ No newline at end of file diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/UserRep.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/UserRep.java new file mode 100644 index 000000000..2fb0334f8 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/UserRep.java @@ -0,0 +1,388 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.xml.XmlKeyValue; + +/** + * To keep certain details of the {@link User} itself hidden from remote clients and make sure instances are only edited + * by users with the correct privilege, this representational version is allowed to be viewed by remote clients and + * simply wraps all public data from the {@link User} + * + * @author Robert von Burg + */ +@XmlRootElement(name = "User") +@XmlAccessorType(XmlAccessType.NONE) +public class UserRep implements Serializable { + + private static final long serialVersionUID = 1L; + + @XmlAttribute(name = "userId") + private String userId; + + @XmlAttribute(name = "username") + private String username; + + @XmlAttribute(name = "firstname") + private String firstname; + + @XmlAttribute(name = "lastname") + private String lastname; + + @XmlAttribute(name = "userState") + private UserState userState; + + @XmlAttribute(name = "locale") + private Locale locale; + + @XmlElement(name = "roles") + private Set roles; + + @XmlElement(name = "properties") + private List properties; + + /** + * Default constructor + * + * @param userId + * the user's id + * @param username + * the user's login name + * @param firstname + * the user's first name + * @param lastname + * the user's last name + * @param userState + * the user's {@link UserState} + * @param roles + * the set of {@link Role}s assigned to this user + * @param locale + * the user's {@link Locale} + * @param propertyMap + * a {@link Map} containing string value pairs of properties for this user + */ + public UserRep(String userId, String username, String firstname, String lastname, UserState userState, + Set roles, Locale locale, Map propertyMap) { + this.userId = userId; + this.username = username; + this.firstname = firstname; + this.lastname = lastname; + this.userState = userState; + this.roles = roles; + this.locale = locale; + this.properties = propertyMap == null ? new ArrayList<>() : XmlKeyValue.valueOf(propertyMap); + } + + /** + * + */ + @SuppressWarnings("unused") + private UserRep() { + // No arg constructor for JAXB + } + + /** + * Validates that all required fields are set + */ + public void validate() { + + if (StringHelper.isEmpty(this.userId)) + throw new PrivilegeException("userId is null or empty"); //$NON-NLS-1$ + + if (StringHelper.isEmpty(this.username)) + throw new PrivilegeException("username is null or empty"); //$NON-NLS-1$ + + if (this.userState == null) + throw new PrivilegeException("userState is null"); //$NON-NLS-1$ + + if (StringHelper.isEmpty(this.firstname)) + throw new PrivilegeException("firstname is null or empty"); //$NON-NLS-1$ + + if (StringHelper.isEmpty(this.lastname)) + throw new PrivilegeException("lastname is null or empty"); //$NON-NLS-1$ + + if (this.roles == null || this.roles.isEmpty()) + throw new PrivilegeException("roles is null or empty"); //$NON-NLS-1$ + } + + /** + * @return the userId + */ + public String getUserId() { + return this.userId; + } + + /** + * Set the userId + * + * @param userId + * to set + */ + public void setUserId(String userId) { + this.userId = userId; + } + + /** + * @return the username + */ + public String getUsername() { + return this.username; + } + + /** + * @param username + * the username to set + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * @return the firstname + */ + public String getFirstname() { + return this.firstname; + } + + /** + * @param firstname + * the firstname to set + */ + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + /** + * @return the lastname + */ + public String getLastname() { + return this.lastname; + } + + /** + * @param lastname + * the lastname to set + */ + public void setLastname(String lastname) { + this.lastname = lastname; + } + + /** + * @return the userState + */ + public UserState getUserState() { + return this.userState; + } + + /** + * @param userState + * the userState to set + */ + public void setUserState(UserState userState) { + this.userState = userState; + } + + /** + * @return the roles + */ + public Set getRoles() { + return this.roles; + } + + /** + * @param roles + * the roles to set + */ + public void setRoles(Set roles) { + this.roles = roles; + } + + /** + * @return the locale + */ + public Locale getLocale() { + return this.locale; + } + + /** + * @param locale + * the locale to set + */ + public void setLocale(Locale locale) { + this.locale = locale; + } + + /** + * Returns the property with the given key + * + * @param key + * the key for which the property is to be returned + * + * @return the property with the given key, or null if the property is not defined + */ + public String getProperty(String key) { + if (this.properties == null) + return null; + for (XmlKeyValue keyValue : this.properties) { + if (keyValue.getKey().equals(key)) + return keyValue.getValue(); + } + return null; + } + + /** + * Set the property with the key to the value + * + * @param key + * the key of the property to set + * @param value + * the value of the property to set + */ + public void setProperty(String key, String value) { + if (this.properties == null) + this.properties = new ArrayList<>(); + + boolean updated = false; + + for (XmlKeyValue keyValue : this.properties) { + if (keyValue.getKey().equals(key)) { + keyValue.setValue(value); + updated = true; + } + } + + if (!updated) { + this.properties.add(new XmlKeyValue(key, value)); + } + } + + /** + * Returns the {@link Set} of keys of all properties + * + * @return the {@link Set} of keys of all properties + */ + public Set getPropertyKeySet() { + if (this.properties == null) + return new HashSet<>(); + Set keySet = new HashSet<>(this.properties.size()); + for (XmlKeyValue keyValue : this.properties) { + keySet.add(keyValue.getKey()); + } + return keySet; + } + + /** + * Returns the map of properties + * + * @return the map of properties + */ + public Map getPropertyMap() { + if (this.properties == null) + return new HashMap<>(); + return XmlKeyValue.toMap(this.properties); + } + + /** + * Returns the string map properties of this user as a list of {@link XmlKeyValue} elements + * + * @return the string map properties of this user as a list of {@link XmlKeyValue} elements + */ + @XmlElement(name = "properties") + public List getProperties() { + return this.properties == null ? new ArrayList<>() : this.properties; + } + + /** + * Sets the string map properties of this user from the given list of {@link XmlKeyValue} + * + * @param values + * the list of {@link XmlKeyValue} from which to set the properties + */ + public void setProperties(List values) { + this.properties = values; + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("UserRep [userId="); + builder.append(this.userId); + builder.append(", username="); + builder.append(this.username); + builder.append(", firstname="); + builder.append(this.firstname); + builder.append(", lastname="); + builder.append(this.lastname); + builder.append(", userState="); + builder.append(this.userState); + builder.append(", locale="); + builder.append(this.locale); + builder.append(", roles="); + builder.append(this.roles); + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.username == null) ? 0 : this.username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + UserRep other = (UserRep) obj; + if (this.username == null) { + if (other.username != null) + return false; + } else if (!this.username.equals(other.username)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/UserState.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/UserState.java new file mode 100644 index 000000000..12da7a2a6 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/UserState.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model; + +import li.strolch.privilege.model.internal.User; + +/** + * The {@link UserState} enum defines the different states a {@link User} can have: + *
    + *
  • NEW - the user is new, and cannot login
  • + *
  • ENABLED - the user has been enabled, meaning a password has been set and the user has at least one role assigned + * and may thus login
  • + *
  • DISABLED - the user been disabled by an administrator
  • + *
  • EXPIRED - the user has automatically expired through a predefined time
  • + *
+ * + * @author Robert von Burg + * + */ +public enum UserState { + /** + * the user is new, and cannot login + */ + NEW, + /** + * the user has been enabled, meaning a password has been set and the user has at least one role assigned and may + * thus login + */ + ENABLED, + /** + * the user been disabled by an administrator + */ + DISABLED, + /** + * the user has automatically expired through a predefined time + */ + EXPIRED, + + /** + * This is the System user state which is special and thus exempted from normal uses + */ + SYSTEM; + + public boolean isSystem() { + return this == UserState.SYSTEM; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/PrivilegeContainerModel.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/PrivilegeContainerModel.java new file mode 100644 index 000000000..a85371886 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/PrivilegeContainerModel.java @@ -0,0 +1,188 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model.internal; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.policy.PrivilegePolicy; + +/** + * This class is used during XML parsing to hold the model before it is properly validated and made accessible through + * the {@link PrivilegeHandler} + * + *

+ * Note: This is an internal object which is not to be serialized or passed to clients + *

+ * + * @author Robert von Burg + */ +public class PrivilegeContainerModel { + + private String encryptionHandlerClassName; + private Map encryptionHandlerParameterMap; + private String persistenceHandlerClassName; + private Map persistenceHandlerParameterMap; + private Map parameterMap; + private Map> policies; + + /** + * Default constructor + */ + public PrivilegeContainerModel() { + this.policies = new HashMap<>(); + } + + /** + * @return the parameterMap + */ + public Map getParameterMap() { + return this.parameterMap; + } + + /** + * @param parameterMap + * the parameterMap to set + */ + public void setParameterMap(Map parameterMap) { + this.parameterMap = parameterMap; + } + + /** + * @return the encryptionHandlerClassName + */ + public String getEncryptionHandlerClassName() { + return this.encryptionHandlerClassName; + } + + /** + * @param encryptionHandlerClassName + * the encryptionHandlerClassName to set + */ + public void setEncryptionHandlerClassName(String encryptionHandlerClassName) { + this.encryptionHandlerClassName = encryptionHandlerClassName; + } + + /** + * @return the encryptionHandlerParameterMap + */ + public Map getEncryptionHandlerParameterMap() { + return this.encryptionHandlerParameterMap; + } + + /** + * @param encryptionHandlerParameterMap + * the encryptionHandlerParameterMap to set + */ + public void setEncryptionHandlerParameterMap(Map encryptionHandlerParameterMap) { + this.encryptionHandlerParameterMap = encryptionHandlerParameterMap; + } + + /** + * @return the persistenceHandlerClassName + */ + public String getPersistenceHandlerClassName() { + return this.persistenceHandlerClassName; + } + + /** + * @param persistenceHandlerClassName + * the persistenceHandlerClassName to set + */ + public void setPersistenceHandlerClassName(String persistenceHandlerClassName) { + this.persistenceHandlerClassName = persistenceHandlerClassName; + } + + /** + * @return the persistenceHandlerParameterMap + */ + public Map getPersistenceHandlerParameterMap() { + return this.persistenceHandlerParameterMap; + } + + /** + * @param persistenceHandlerParameterMap + * the persistenceHandlerParameterMap to set + */ + public void setPersistenceHandlerParameterMap(Map persistenceHandlerParameterMap) { + this.persistenceHandlerParameterMap = persistenceHandlerParameterMap; + } + + /** + * @param privilegeName + * @param policyClassName + */ + public void addPolicy(String privilegeName, String policyClassName) { + + try { + + // load class and try to create a new instance + @SuppressWarnings("unchecked") + Class clazz = (Class) Class.forName(policyClassName); + clazz.newInstance(); + + this.policies.put(privilegeName, clazz); + + } catch (InstantiationException e) { + String msg = "Configured Privilege Policy {0} with class {1} could not be instantiated."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName, policyClassName); + throw new PrivilegeException(msg, e); + } catch (IllegalAccessException e) { + String msg = "Configured Privilege Policy {0} with class {1} can not be accessed."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName, policyClassName); + throw new PrivilegeException(msg, e); + } catch (ClassNotFoundException e) { + String msg = "Configured Privilege Policy {0} with class {1} does not exist."; //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName, policyClassName); + throw new PrivilegeException(msg, e); + } + } + + /** + * @return the policies + */ + public Map> getPolicies() { + return this.policies; + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PrivilegeContainerModel [encryptionHandlerClassName="); + builder.append(this.encryptionHandlerClassName); + builder.append(", encryptionHandlerParameterMap="); + builder.append(this.encryptionHandlerParameterMap.size()); + builder.append(", persistenceHandlerClassName="); + builder.append(this.persistenceHandlerClassName); + builder.append(", persistenceHandlerParameterMap="); + builder.append(this.persistenceHandlerParameterMap.size()); + builder.append(", parameterMap="); + builder.append(this.parameterMap.size()); + builder.append(", policies="); + builder.append(this.policies.size()); + builder.append("]"); + return builder.toString(); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/PrivilegeImpl.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/PrivilegeImpl.java new file mode 100644 index 000000000..3a5e45068 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/PrivilegeImpl.java @@ -0,0 +1,229 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model.internal; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.policy.PrivilegePolicy; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it + * which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a + * {@link PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow + * lists configured which is used to evaluate if privilege is granted to a {@link Restrictable} + *

+ * + *

+ * {@link IPrivilege}s have allow and deny rules which the configured {@link PrivilegeHandler} uses to + *

+ * + *

+ * Note: This is an internal object which is not to be serialized or passed to clients, {@link PrivilegeRep}s are used + * for that + *

+ * + * @author Robert von Burg + */ +public final class PrivilegeImpl implements IPrivilege { + + private final String name; + private final String policy; + private final boolean allAllowed; + private final Set denyList; + private final Set allowList; + + /** + * Default constructor + * + * @param name + * the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler} + * @param policy + * the {@link PrivilegePolicy} configured to evaluate if the privilege is granted. If null, then + * privilege is granted + * @param allAllowed + * a boolean defining if a {@link Role} with this {@link PrivilegeImpl} has unrestricted access to a + * {@link Restrictable} in which case the deny and allow lists are ignored and can be null + * @param denyList + * a list of deny rules for this {@link PrivilegeImpl}, can be null if all allowed + * @param allowList + * a list of allow rules for this {@link PrivilegeImpl}, can be null if all allowed + */ + public PrivilegeImpl(String name, String policy, boolean allAllowed, Set denyList, Set allowList) { + + if (StringHelper.isEmpty(name)) { + throw new PrivilegeException("No name defined!"); //$NON-NLS-1$ + } + if (StringHelper.isEmpty(policy)) { + throw new PrivilegeException(MessageFormat.format("Policy may not be empty for Privilege {0}!", name)); //$NON-NLS-1$ + } + if (denyList == null) { + throw new PrivilegeException(MessageFormat.format("denyList is null for Privilege {0}!", name)); //$NON-NLS-1$ + } + if (allowList == null) { + throw new PrivilegeException(MessageFormat.format("allowList is null for Privilege {0}!", name)); //$NON-NLS-1$ + } + + this.name = name; + this.allAllowed = allAllowed; + this.policy = policy; + this.denyList = Collections.unmodifiableSet(denyList); + this.allowList = Collections.unmodifiableSet(allowList); + } + + /** + * Constructs a {@link PrivilegeImpl} from the {@link PrivilegeRep} + * + * @param privilegeRep + * the {@link PrivilegeRep} from which to create the {@link PrivilegeImpl} + */ + public PrivilegeImpl(PrivilegeRep privilegeRep) { + this(privilegeRep.getName(), privilegeRep.getPolicy(), privilegeRep.isAllAllowed(), privilegeRep.getDenyList(), + privilegeRep.getAllowList()); + } + + /** + * @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients + */ + @Override + public PrivilegeRep asPrivilegeRep() { + return new PrivilegeRep(this.name, this.policy, this.allAllowed, new HashSet<>(this.denyList), + new HashSet<>(this.allowList)); + } + + /** + * @return the name + */ + @Override + public String getName() { + return this.name; + } + + /** + * @return the policy + */ + @Override + public String getPolicy() { + return this.policy; + } + + /** + * @return the allAllowed + */ + @Override + public boolean isAllAllowed() { + return this.allAllowed; + } + + /** + * @return the allowList + */ + @Override + public Set getAllowList() { + return this.allowList; + } + + /** + * @return the denyList + */ + @Override + public Set getDenyList() { + return this.denyList; + } + + /** + * @return true if there are values in the allow list + */ + @Override + public boolean hasAllowed() { + return !this.allowList.isEmpty(); + } + + /** + * @return if the value is in the allow list + */ + @Override + public boolean isAllowed(String value) { + return this.allowList.contains(value); + } + + /** + * @return true if there are values in the deny list + */ + @Override + public boolean hasDenied() { + return !this.allowList.isEmpty(); + } + + /** + * @return true if the value is in the deny list + */ + @Override + public boolean isDenied(String value) { + return this.denyList.contains(value); + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Privilege [name="); + builder.append(this.name); + builder.append(", policy="); + builder.append(this.policy); + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PrivilegeImpl other = (PrivilegeImpl) obj; + if (this.name == null) { + if (other.name != null) + return false; + } else if (!this.name.equals(other.name)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/Role.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/Role.java new file mode 100644 index 000000000..1d3fc6c87 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/Role.java @@ -0,0 +1,187 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.RoleRep; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * A {@link User} is assigned a set of roles. These roles have a set of privileges assigned to them by name and they + * define the privileges granted to a user with this role + *

+ * + *

+ * Note: This is an internal object which is not to be serialized or passed to clients, {@link RoleRep}s are used for + * that + *

+ * + * @author Robert von Burg + */ +public final class Role { + + private final String name; + private final Map privilegeMap; + + /** + * Default constructor + * + * @param name + * the name of the role + * @param privilegeMap + * a map of {@link IPrivilege}s granted to this role + */ + public Role(String name, Map privilegeMap) { + + if (StringHelper.isEmpty(name)) { + throw new PrivilegeException("No name defined!"); //$NON-NLS-1$ + } + if (privilegeMap == null) { + throw new PrivilegeException("No privileges defined!"); //$NON-NLS-1$ + } + + this.name = name; + this.privilegeMap = Collections.unmodifiableMap(privilegeMap); + } + + /** + * Construct {@link Role} from its representation {@link RoleRep} + * + * @param roleRep + * the representation from which to create the {@link Role} + */ + public Role(RoleRep roleRep) { + + String name = roleRep.getName(); + if (StringHelper.isEmpty(name)) { + throw new PrivilegeException("No name defined!"); //$NON-NLS-1$ + } + + if (roleRep.getPrivileges() == null) { + throw new PrivilegeException("Privileges may not be null!"); //$NON-NLS-1$ + } + + // build privileges from rep + Map privilegeMap = new HashMap<>(roleRep.getPrivileges().size()); + for (PrivilegeRep privilege : roleRep.getPrivileges()) { + privilegeMap.put(privilege.getName(), new PrivilegeImpl(privilege)); + } + + this.name = name; + this.privilegeMap = Collections.unmodifiableMap(privilegeMap); + } + + /** + * @return the name + */ + public String getName() { + return this.name; + } + + /** + * Returns the {@link Set} of names for the currently stored {@link IPrivilege Privileges} + * + * @return the {@link Set} of names for the currently stored {@link IPrivilege Privileges} + */ + public Set getPrivilegeNames() { + return this.privilegeMap.keySet(); + } + + /** + * Returns the {@link IPrivilege} for the given name, null if it does not exist + * + * @return the {@link IPrivilege} for the given name, null if it does not exist + */ + public IPrivilege getPrivilege(String name) { + return this.privilegeMap.get(name); + } + + /** + * Determines if this {@link Role} has the {@link IPrivilege} with the given name + * + * @param name + * the name of the {@link IPrivilege} + * + * @return true if this {@link Role} has the {@link IPrivilege} with the given name + */ + public boolean hasPrivilege(String name) { + return this.privilegeMap.containsKey(name); + } + + /** + * @return a {@link RoleRep} which is a representation of this object used to serialize and view on clients + */ + public RoleRep asRoleRep() { + List privileges = new ArrayList<>(); + for (Entry entry : this.privilegeMap.entrySet()) { + privileges.add(entry.getValue().asPrivilegeRep()); + } + return new RoleRep(this.name, privileges); + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Role [name="); + builder.append(this.name); + builder.append(", privileges="); + builder.append(this.privilegeMap.keySet()); + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Role other = (Role) obj; + if (this.name == null) { + if (other.name != null) + return false; + } else if (!this.name.equals(other.name)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/User.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/User.java new file mode 100644 index 000000000..70cd57b5b --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/model/internal/User.java @@ -0,0 +1,291 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.model.internal; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.UserRep; +import li.strolch.privilege.model.UserState; +import li.strolch.utils.helper.StringHelper; + +/** + * This class defines the actual login information for a given user which can be granted privileges. Every user is + * granted a set of {@link Role}s and has a {@link UserState} including detail information like first name and lastname + * + *

+ * Note: This is an internal object which is not to be serialized or passed to clients, {@link UserRep}s are used for + * that + *

+ * + * @author Robert von Burg + */ +public final class User { + + private final String userId; + + private final String username; + private final String password; + + private final String firstname; + private final String lastname; + + private final UserState userState; + + private final Set roles; + + private final Map propertyMap; + + private final Locale locale; + + /** + * Default constructor + * + * @param userId + * the user's id + * @param username + * the user's login name + * @param password + * the user's password (hashed) + * @param firstname + * the user's first name + * @param lastname + * the user's lastname + * @param userState + * the user's {@link UserState} + * @param roles + * the set of {@link Role}s assigned to this user + * @param locale + * the user's {@link Locale} + * @param propertyMap + * a {@link Map} containing string value pairs of properties for this user + */ + public User(String userId, String username, String password, String firstname, String lastname, + UserState userState, Set roles, Locale locale, Map propertyMap) { + + if (StringHelper.isEmpty(userId)) { + throw new PrivilegeException("No UserId defined!"); //$NON-NLS-1$ + } + if (userState == null) { + throw new PrivilegeException("No userState defined!"); //$NON-NLS-1$ + } + if (StringHelper.isEmpty(username)) { + throw new PrivilegeException("No username defined!"); //$NON-NLS-1$ + } + if (userState != UserState.SYSTEM) { + if (StringHelper.isEmpty(lastname)) { + throw new PrivilegeException("No lastname defined!"); //$NON-NLS-1$ + } + if (StringHelper.isEmpty(firstname)) { + throw new PrivilegeException("No firstname defined!"); //$NON-NLS-1$ + } + } + + // password may be null, meaning not able to login + // roles may be null, meaning not able to login and must be added later + // locale may be null, meaning use system default + // properties may be null, meaning no properties + + this.userId = userId; + + this.username = username; + this.password = StringHelper.isEmpty(password) ? null : password; + this.userState = userState; + + this.firstname = firstname; + this.lastname = lastname; + + if (roles == null) + this.roles = Collections.emptySet(); + else + this.roles = Collections.unmodifiableSet(new HashSet<>(roles)); + + if (locale == null) + this.locale = Locale.getDefault(); + else + this.locale = locale; + + if (propertyMap == null) + this.propertyMap = Collections.emptyMap(); + else + this.propertyMap = Collections.unmodifiableMap(new HashMap<>(propertyMap)); + } + + /** + * @return the userId + */ + public String getUserId() { + return this.userId; + } + + /** + * @return the username + */ + public String getUsername() { + return this.username; + } + + /** + * Returns the hashed password for this {@link User} + * + * @return the hashed password for this {@link User} + */ + public String getPassword() { + return this.password; + } + + /** + * @return the first name + */ + public String getFirstname() { + return this.firstname; + } + + /** + * @return the last name + */ + public String getLastname() { + return this.lastname; + } + + /** + * @return the userState + */ + public UserState getUserState() { + return this.userState; + } + + /** + * @return the roles + */ + public Set getRoles() { + return this.roles; + } + + /** + * Returns true if this user has the specified role + * + * @param role + * the name of the {@link Role} to check for + * + * @return true if the this user has the specified role + */ + public boolean hasRole(String role) { + return this.roles.contains(role); + } + + /** + * @return the locale + */ + public Locale getLocale() { + return this.locale; + } + + /** + * Returns the property with the given key + * + * @param key + * the key for which the property is to be returned + * + * @return the property with the given key, or null if the property is not defined + */ + public String getProperty(String key) { + return this.propertyMap.get(key); + } + + /** + * Returns the {@link Set} of keys of all properties + * + * @return the {@link Set} of keys of all properties + */ + public Set getPropertyKeySet() { + return this.propertyMap.keySet(); + } + + /** + * Returns the map of properties + * + * @return the map of properties + */ + public Map getProperties() { + return this.propertyMap; + } + + /** + * @return a {@link UserRep} which is a representation of this object used to serialize and view on clients + */ + public UserRep asUserRep() { + return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState, + new HashSet<>(this.roles), this.locale, new HashMap<>(this.propertyMap)); + } + + /** + * Returns a string representation of this object displaying its concrete type and its values + * + * @see java.lang.Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("User [userId="); + builder.append(this.userId); + builder.append(", username="); + builder.append(this.username); + builder.append(", firstname="); + builder.append(this.firstname); + builder.append(", lastname="); + builder.append(this.lastname); + builder.append(", locale="); + builder.append(this.locale); + builder.append(", userState="); + builder.append(this.userState); + builder.append(", roles="); + builder.append(this.roles); + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.userId == null) ? 0 : this.userId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + User other = (User) obj; + if (this.userId == null) { + if (other.userId != null) + return false; + } else if (!this.userId.equals(other.userId)) + return false; + return true; + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/DefaultPrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/DefaultPrivilege.java new file mode 100644 index 000000000..69c6bea21 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/DefaultPrivilege.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.internal.Role; + +/** + * This is a simple implementation of {@link PrivilegePolicy} which uses the {@link Restrictable#getPrivilegeName()} to + * see if a given {@link Role} has the privilege required by the value from {@link Restrictable#getPrivilegeValue()} + * + * @author Robert von Burg + */ +public class DefaultPrivilege implements PrivilegePolicy { + + /** + * The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege + * + * @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(IPrivilege, Restrictable) + */ + @Override + public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) { + PrivilegePolicyHelper.preValidate(privilege, restrictable); + + // get the value on which the action is to be performed + Object object = restrictable.getPrivilegeValue(); + + // DefaultPrivilege policy expects the privilege value to be a string + if (!(object instanceof String)) { + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.nonstring"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); + } + + // if everything is allowed, then no need to carry on + if (privilege.isAllAllowed()) + return; + + String privilegeValue = (String) object; + + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/PrivilegePolicy.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/PrivilegePolicy.java new file mode 100644 index 000000000..fe6daff9e --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/PrivilegePolicy.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; + +/** + *

+ * {@link PrivilegePolicy} implements logic to determine if a {@link User} which has the given {@link Role} and the + * given {@link IPrivilege} has access to the given {@link Restrictable} + *

+ * + *

+ * TODO + *

+ * + * @author Robert von Burg + */ +public interface PrivilegePolicy { + + /** + * Checks if the given {@link Role} and the given {@link IPrivilege} has access to the given {@link Restrictable} + * + * @param context + * the privilege context + * @param privilege + * the {@link IPrivilege} containing the permissions + * @param restrictable + * the {@link Restrictable} to which the user wants access + * + * @throws AccessDeniedException + * if action not allowed + */ + public abstract void validateAction(PrivilegeContext context, IPrivilege privilege, Restrictable restrictable) + throws AccessDeniedException; +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/PrivilegePolicyHelper.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/PrivilegePolicyHelper.java new file mode 100644 index 000000000..e749eed77 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/PrivilegePolicyHelper.java @@ -0,0 +1,80 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +public class PrivilegePolicyHelper { + + public static String preValidate(IPrivilege privilege, Restrictable restrictable) { + if (privilege == null) + throw new PrivilegeException(PrivilegeMessages.getString("Privilege.privilegeNull")); //$NON-NLS-1$ + if (restrictable == null) + throw new PrivilegeException(PrivilegeMessages.getString("Privilege.restrictableNull")); //$NON-NLS-1$ + + // get the PrivilegeName + String privilegeName = restrictable.getPrivilegeName(); + if (StringHelper.isEmpty(privilegeName)) { + String msg = PrivilegeMessages.getString("Privilege.privilegeNameEmpty"); //$NON-NLS-1$ + throw new PrivilegeException(MessageFormat.format(msg, restrictable)); + } + + // we want the privileges names to match + if (!privilege.getName().equals(privilegeName)) { + throw new PrivilegeException(MessageFormat.format( + PrivilegeMessages.getString("Privilege.illegalArgument.privilegeNameMismatch"), //$NON-NLS-1$ + privilege.getName(), privilegeName)); + } + + return privilegeName; + } + + /** + * @param privilege + * @param privilegeValue + */ + public static void checkByAllowDenyValues(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable, + String privilegeValue) { + + // first check values not allowed + if (privilege.isDenied(privilegeValue)) { + // then throw access denied + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), //$NON-NLS-1$ + ctx.getUsername(), privilege.getName(), restrictable.getClass().getName()); + throw new AccessDeniedException(msg); + } + + // now check values allowed + if (privilege.isAllowed(privilegeValue)) + return; + + // default is not allowed + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), //$NON-NLS-1$ + ctx.getUsername(), privilege.getName(), restrictable.getClass().getName()); + throw new AccessDeniedException(msg); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/RoleAccessPrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/RoleAccessPrivilege.java new file mode 100644 index 000000000..e0dfb4676 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/RoleAccessPrivilege.java @@ -0,0 +1,117 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.internal.Role; +import li.strolch.utils.collections.Tuple; +import li.strolch.utils.dbc.DBC; + +/** + * This {@link PrivilegePolicy} expects a {@link Tuple} as {@link Restrictable#getPrivilegeValue()}. The Tuple must + * contain {@link Role} as first and second value. Then the policy decides depending on the user specific privileges + * (see {@link PrivilegeHandler}), uses the basic Allow and Deny to detect if the username of + * the certificate is allowed + * + * @author Robert von Burg + */ +public class RoleAccessPrivilege implements PrivilegePolicy { + + @Override + public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) { + String privilegeName = PrivilegePolicyHelper.preValidate(privilege, restrictable); + + // get the value on which the action is to be performed + Object object = restrictable.getPrivilegeValue(); + + // if the object is null, then it means the validation is that the privilege must exist + if (object == null) + return; + + // RoleAccessPrivilege policy expects the privilege value to be a role + if (!(object instanceof Tuple)) { + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.nontuple"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); + } + + // if everything is allowed, then no need to carry on + if (privilege.isAllAllowed()) + return; + + Tuple tuple = (Tuple) object; + + // get role name as privilege value + Role oldRole = tuple.getFirst(); + Role newRole = tuple.getSecond(); + + switch (privilegeName) { + case PrivilegeHandler.PRIVILEGE_GET_ROLE: { + DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole); + + String privilegeValue = newRole.getName(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + + case PrivilegeHandler.PRIVILEGE_ADD_ROLE: { + DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole); + + String privilegeValue = newRole.getName(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_MODIFY_ROLE: { + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldRole); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole); + + String privilegeValue = newRole.getName(); + DBC.INTERIM.assertEquals("oldRole and newRole names must be the same", oldRole.getName(), privilegeValue); + + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_REMOVE_ROLE: { + DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole); + + String privilegeValue = newRole.getName(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + + default: + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.roleAccessPrivilege.unknownPrivilege"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName); + throw new PrivilegeException(msg); + } + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UserAccessPrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UserAccessPrivilege.java new file mode 100644 index 000000000..ca46ec55e --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UserAccessPrivilege.java @@ -0,0 +1,190 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.internal.User; +import li.strolch.utils.collections.Tuple; +import li.strolch.utils.dbc.DBC; + +/** + * This {@link PrivilegePolicy} expects a {@link Tuple} as {@link Restrictable#getPrivilegeValue()} and then depending + * on the user specific privileges (see {@link PrivilegeHandler}), uses the basic Allow and + * Deny to detect if the username of the certificate is allowed + * + * @author Robert von Burg + */ +public class UserAccessPrivilege implements PrivilegePolicy { + + @Override + public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) { + String privilegeName = PrivilegePolicyHelper.preValidate(privilege, restrictable); + + // get the value on which the action is to be performed + Object object = restrictable.getPrivilegeValue(); + + // if the object is null, then it means the validation is that the privilege must exist + if (object == null) + return; + + // RoleAccessPrivilege policy expects the privilege value to be a role + if (!(object instanceof Tuple)) { + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.nontuple"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); + } + + // if everything is allowed, then no need to carry on + if (privilege.isAllAllowed()) + return; + + Tuple tuple = (Tuple) object; + + switch (privilegeName) { + case PrivilegeHandler.PRIVILEGE_GET_USER: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUsername(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_ADD_USER: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUsername(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_REMOVE_USER: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUsername(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_MODIFY_USER: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUsername(); + DBC.INTERIM.assertEquals("oldUser and newUser names must be the same", oldUser.getUsername(), + privilegeValue); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_ADD_ROLE_TO_USER: { + User user = tuple.getFirst(); + String roleName = tuple.getSecond(); + + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", user); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", roleName); + + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, roleName); + + break; + } + case PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER: { + User user = tuple.getFirst(); + String roleName = tuple.getSecond(); + + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", user); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", roleName); + + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, roleName); + + break; + } + case PrivilegeHandler.PRIVILEGE_SET_USER_STATE: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUserState().name(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_SET_USER_LOCALE: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUsername(); + + // user can set their own locale + if (ctx.getUsername().equals(privilegeValue)) + return; + + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + case PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD: { + User oldUser = tuple.getFirst(); + User newUser = tuple.getSecond(); + + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + + String privilegeValue = newUser.getUsername(); + + // user can set their own password + if (ctx.getUsername().equals(privilegeValue)) + return; + + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + + break; + } + + default: + String msg = PrivilegeMessages.getString("Privilege.userAccessPrivilege.unknownPrivilege"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName, this.getClass().getName()); + throw new PrivilegeException(msg); + } + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UserAccessWithSameOrganisationPrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UserAccessWithSameOrganisationPrivilege.java new file mode 100644 index 000000000..5f02ae266 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UserAccessWithSameOrganisationPrivilege.java @@ -0,0 +1,115 @@ +/* + * Copyright 2015 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.internal.User; +import li.strolch.utils.collections.Tuple; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; + +/** + * Validates that any access to a privilege User is done only by users in the same organisation + * + * @author Robert von Burg + */ +public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege { + + private static final String PARAM_ORGANISATION = "organisation"; + + @Override + public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) { + String privilegeName = PrivilegePolicyHelper.preValidate(privilege, restrictable); + + // get the value on which the action is to be performed + Object object = restrictable.getPrivilegeValue(); + + // RoleAccessPrivilege policy expects the privilege value to be a role + if (!(object instanceof Tuple)) { + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.nontuple"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); + } + + // get user organisation + String userOrg = ctx.getCertificate().getProperty(PARAM_ORGANISATION); + if (StringHelper.isEmpty(userOrg)) { + throw new AccessDeniedException("No organisation configured for user " + ctx.getUsername()); + } + + Tuple tuple = (Tuple) object; + + switch (privilegeName) { + case PrivilegeHandler.PRIVILEGE_GET_USER: + case PrivilegeHandler.PRIVILEGE_ADD_USER: + case PrivilegeHandler.PRIVILEGE_MODIFY_USER: + case PrivilegeHandler.PRIVILEGE_REMOVE_USER: { + + // make sure old user has same organisation + User oldUser = tuple.getFirst(); + if (oldUser != null) { + String oldOrg = oldUser.getProperty(PARAM_ORGANISATION); + if (!userOrg.equals(oldOrg)) { + throw new AccessDeniedException("User " + ctx.getUsername() + + " may not access users outside of their organisation: " + userOrg + " / " + oldOrg); + } + } + + // make sure new user has same organisation + User newUser = tuple.getSecond(); + DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser); + String newdOrg = newUser.getProperty(PARAM_ORGANISATION); + if (!userOrg.equals(newdOrg)) { + throw new AccessDeniedException("User " + ctx.getUsername() + + " may not access users outside of their organisations: " + userOrg + " / " + newdOrg); + } + + break; + } + case PrivilegeHandler.PRIVILEGE_ADD_ROLE_TO_USER: + case PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER: { + + User user = tuple.getFirst(); + DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", user); + String org = user.getProperty(PARAM_ORGANISATION); + if (!userOrg.equals(org)) { + throw new AccessDeniedException("User " + ctx.getUsername() + + " may not access users outside of their organisation: " + userOrg + " / " + org); + } + + break; + } + + default: + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.userAccessPrivilege.unknownPrivilege"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, privilegeName); + throw new PrivilegeException(msg); + } + + // now delegate the rest of the validation to the super class + super.validateAction(ctx, privilege, restrictable); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UsernameFromCertificatePrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UsernameFromCertificatePrivilege.java new file mode 100644 index 000000000..a95d2d11e --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UsernameFromCertificatePrivilege.java @@ -0,0 +1,65 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; + +/** + *

+ * This {@link PrivilegePolicy} expects a {@link Certificate} as {@link Restrictable#getPrivilegeValue()} and uses the + * basic Allow and Deny to detect if the username of the certificate is allowed. + *

+ * + *

+ * The {@link Certificate} as privilegeValue is not to be confused with the {@link Certificate} of the current user. + * This certificate is of the user to which access is request, i.e. modifying the session of a logged in user. + *

+ * + * @author Robert von Burg + */ +public class UsernameFromCertificatePrivilege implements PrivilegePolicy { + + @Override + public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) { + PrivilegePolicyHelper.preValidate(privilege, restrictable); + + // get the value on which the action is to be performed + Object object = restrictable.getPrivilegeValue(); + + // RoleAccessPrivilege policy expects the privilege value to be a role + if (!(object instanceof Certificate)) { + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.noncertificate"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); + } + + // if everything is allowed, then no need to carry on + if (privilege.isAllAllowed()) + return; + + Certificate cert = (Certificate) object; + String privilegeValue = cert.getUsername(); + PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UsernameFromCertificateWithSameOrganisationPrivilege.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UsernameFromCertificateWithSameOrganisationPrivilege.java new file mode 100644 index 000000000..79ceb086d --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/policy/UsernameFromCertificateWithSameOrganisationPrivilege.java @@ -0,0 +1,79 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.policy; + +import java.text.MessageFormat; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.Restrictable; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * This {@link PrivilegePolicy} expects a {@link Certificate} as {@link Restrictable#getPrivilegeValue()} and uses the + * basic Allow and Deny to detect if the username of the certificate is allowed. + *

+ * + *

+ * The {@link Certificate} as privilegeValue is not to be confused with the {@link Certificate} of the current user. + * This certificate is of the user to which access is request, i.e. modifying the session of a logged in user. + *

+ * + * @author Robert von Burg + */ +public class UsernameFromCertificateWithSameOrganisationPrivilege extends UsernameFromCertificatePrivilege { + + private static final String PARAM_ORGANISATION = "organisation"; + + @Override + public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) { + PrivilegePolicyHelper.preValidate(privilege, restrictable); + + // get the value on which the action is to be performed + Object object = restrictable.getPrivilegeValue(); + + // RoleAccessPrivilege policy expects the privilege value to be a role + if (!(object instanceof Certificate)) { + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.noncertificate"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); + } + + // get object + Certificate cert = (Certificate) object; + + // get user organisation + String userOrg = ctx.getCertificate().getProperty(PARAM_ORGANISATION); + if (StringHelper.isEmpty(userOrg)) { + throw new AccessDeniedException("No organisation configured for user " + ctx.getUsername()); + } + // assert same organisation + String org = cert.getProperty(PARAM_ORGANISATION); + if (!userOrg.equals(org)) { + throw new AccessDeniedException("User " + ctx.getUsername() + + " may not access users outside of their organisation: " + userOrg + " / " + org); + } + + // now delegate the rest of the validation to the super class + super.validateAction(ctx, privilege, restrictable); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/CertificateStubsDomWriter.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/CertificateStubsDomWriter.java new file mode 100644 index 000000000..4725b4f0f --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/CertificateStubsDomWriter.java @@ -0,0 +1,79 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.io.OutputStream; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.Certificate; +import li.strolch.utils.helper.XmlHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; + +/** + * @author Robert von Burg + */ +public class CertificateStubsDomWriter { + + private List certificates; + private OutputStream outputStream; + + public CertificateStubsDomWriter(List certificates, OutputStream outputStream) { + this.certificates = certificates; + this.outputStream = outputStream; + } + + public void write() { + + // create document root + Document doc = XmlHelper.createDocument(); + Element rootElement = doc.createElement(XmlConstants.XML_ROOT_CERTIFICATES); + doc.appendChild(rootElement); + + this.certificates.stream().sorted((c1, c2) -> c1.getSessionId().compareTo(c2.getSessionId())).forEach(cert -> { + + // create the certificate element + Element certElement = doc.createElement(XmlConstants.XML_CERTIFICATE); + rootElement.appendChild(certElement); + + // sessionId; + certElement.setAttribute(XmlConstants.XML_ATTR_SESSION_ID, cert.getSessionId()); + + // username; + certElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, cert.getUsername()); + + // authToken; + certElement.setAttribute(XmlConstants.XML_ATTR_AUTH_TOKEN, cert.getAuthToken()); + + // locale; + certElement.setAttribute(XmlConstants.XML_ATTR_LOCALE, cert.getLocale().toString()); + + // loginTime; + certElement.setAttribute(XmlConstants.XML_ATTR_LOGIN_TIME, + ISO8601FormatFactory.getInstance().formatDate(cert.getLoginTime())); + + // lastAccess; + certElement.setAttribute(XmlConstants.XML_ATTR_LAST_ACCESS, + ISO8601FormatFactory.getInstance().formatDate(cert.getLastAccess())); + }); + + // write the container file to disk + XmlHelper.writeDocument(doc, this.outputStream); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/CertificateStubsSaxReader.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/CertificateStubsSaxReader.java new file mode 100644 index 000000000..ff1f95121 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/CertificateStubsSaxReader.java @@ -0,0 +1,114 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.XmlHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; + +/** + * @author Robert von Burg + */ +public class CertificateStubsSaxReader extends DefaultHandler { + + private InputStream inputStream; + private List stubs; + + public CertificateStubsSaxReader(InputStream inputStream) { + this.inputStream = inputStream; + } + + public List read() { + this.stubs = new ArrayList<>(); + XmlHelper.parseDocument(this.inputStream, this); + return stubs; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + switch (qName) { + case XmlConstants.XML_ROOT_CERTIFICATES: + break; + case XmlConstants.XML_CERTIFICATE: + + CertificateStub stub = new CertificateStub(); + stub.sessionId = attributes.getValue(XmlConstants.XML_ATTR_SESSION_ID); + stub.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME); + stub.authToken = attributes.getValue(XmlConstants.XML_ATTR_AUTH_TOKEN); + stub.locale = new Locale(attributes.getValue(XmlConstants.XML_ATTR_LOCALE)); + stub.loginTime = ISO8601FormatFactory.getInstance() + .parseDate(attributes.getValue(XmlConstants.XML_ATTR_LOGIN_TIME)); + stub.lastAccess = ISO8601FormatFactory.getInstance() + .parseDate(attributes.getValue(XmlConstants.XML_ATTR_LAST_ACCESS)); + + DBC.INTERIM.assertNotEmpty("sessionId missing on sessions data!", stub.sessionId); + DBC.INTERIM.assertNotEmpty("username missing on sessions data!", stub.username); + DBC.INTERIM.assertNotEmpty("authToken missing on sessions data!", stub.authToken); + + this.stubs.add(stub); + break; + + default: + throw new PrivilegeException("Unhandled tag " + qName); + } + } + + public class CertificateStub { + private String sessionId; + private String username; + private String authToken; + private Locale locale; + private Date loginTime; + private Date lastAccess; + + public String getSessionId() { + return sessionId; + } + + public String getUsername() { + return username; + } + + public String getAuthToken() { + return authToken; + } + + public Locale getLocale() { + return locale; + } + + public Date getLoginTime() { + return loginTime; + } + + public Date getLastAccess() { + return lastAccess; + } + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/ElementParser.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/ElementParser.java new file mode 100644 index 000000000..149d70212 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/ElementParser.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +// TODO write JavaDoc... +public interface ElementParser { + + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException; + + public void characters(char[] ch, int start, int length) throws SAXException; + + public void endElement(String uri, String localName, String qName) throws SAXException; + + public void notifyChild(ElementParser child); +} \ No newline at end of file diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/ElementParserAdapter.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/ElementParserAdapter.java new file mode 100644 index 000000000..a9716e7a2 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/ElementParserAdapter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +public abstract class ElementParserAdapter implements ElementParser { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + // empty implementation + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + // empty implementation + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + // empty implementation + } + + @Override + public void notifyChild(ElementParser child) { + // empty implementation + } +} \ No newline at end of file diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeConfigDomWriter.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeConfigDomWriter.java new file mode 100644 index 000000000..97dfb3458 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeConfigDomWriter.java @@ -0,0 +1,115 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.io.File; +import java.util.Map.Entry; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.internal.PrivilegeContainerModel; +import li.strolch.privilege.policy.PrivilegePolicy; +import li.strolch.utils.helper.XmlHelper; + +/** + * @author Robert von Burg + * + */ +public class PrivilegeConfigDomWriter { + + private final PrivilegeContainerModel containerModel; + private final File configFile; + + /** + * + */ + public PrivilegeConfigDomWriter(PrivilegeContainerModel containerModel, File configFile) { + this.containerModel = containerModel; + this.configFile = configFile; + } + + /** + * + */ + public void write() { + + // create document root + Document doc = XmlHelper.createDocument(); + Element rootElement = doc.createElement(XmlConstants.XML_ROOT_PRIVILEGE); + doc.appendChild(rootElement); + + Element containerElement = doc.createElement(XmlConstants.XML_CONTAINER); + rootElement.appendChild(containerElement); + + Element parameterElement; + Element parametersElement; + + // Parameters + parametersElement = doc.createElement(XmlConstants.XML_PARAMETERS); + containerElement.appendChild(parametersElement); + for (Entry entry : this.containerModel.getParameterMap().entrySet()) { + parameterElement = doc.createElement(XmlConstants.XML_PARAMETER); + parameterElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey()); + parameterElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue()); + parametersElement.appendChild(parameterElement); + } + + // create EncryptionHandler + Element encryptionHandlerElem = doc.createElement(XmlConstants.XML_HANDLER_ENCRYPTION); + containerElement.appendChild(encryptionHandlerElem); + encryptionHandlerElem.setAttribute(XmlConstants.XML_ATTR_CLASS, + this.containerModel.getEncryptionHandlerClassName()); + // Parameters + parametersElement = doc.createElement(XmlConstants.XML_PARAMETERS); + encryptionHandlerElem.appendChild(parametersElement); + for (Entry entry : this.containerModel.getEncryptionHandlerParameterMap().entrySet()) { + parameterElement = doc.createElement(XmlConstants.XML_PARAMETER); + parameterElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey()); + parameterElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue()); + parametersElement.appendChild(parameterElement); + } + + // create PersistenceHandler + Element persistenceHandlerElem = doc.createElement(XmlConstants.XML_HANDLER_PERSISTENCE); + containerElement.appendChild(persistenceHandlerElem); + persistenceHandlerElem.setAttribute(XmlConstants.XML_ATTR_CLASS, + this.containerModel.getPersistenceHandlerClassName()); + // Parameters + parametersElement = doc.createElement(XmlConstants.XML_PARAMETERS); + persistenceHandlerElem.appendChild(parametersElement); + for (Entry entry : this.containerModel.getPersistenceHandlerParameterMap().entrySet()) { + parameterElement = doc.createElement(XmlConstants.XML_PARAMETER); + parameterElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey()); + parameterElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue()); + parametersElement.appendChild(parameterElement); + } + + // Policies + Element policiesElem = doc.createElement(XmlConstants.XML_POLICIES); + rootElement.appendChild(policiesElem); + for (Entry> entry : this.containerModel.getPolicies().entrySet()) { + Element policyElem = doc.createElement(XmlConstants.XML_POLICY); + policyElem.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey()); + policyElem.setAttribute(XmlConstants.XML_ATTR_CLASS, entry.getValue().getName()); + policiesElem.appendChild(policyElem); + } + + // write the container file to disk + XmlHelper.writeDocument(doc, this.configFile); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeConfigSaxReader.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeConfigSaxReader.java new file mode 100644 index 000000000..0a266ad1a --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeConfigSaxReader.java @@ -0,0 +1,181 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.internal.PrivilegeContainerModel; + +/** + * @author Robert von Burg + */ +public class PrivilegeConfigSaxReader extends DefaultHandler { + + private Deque buildersStack = new ArrayDeque<>(); + + private PrivilegeContainerModel containerModel; + + public PrivilegeConfigSaxReader(PrivilegeContainerModel containerModel) { + this.containerModel = containerModel; + } + + public PrivilegeContainerModel getContainerModel() { + return this.containerModel; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + if (qName.equals(XmlConstants.XML_CONTAINER)) { + this.buildersStack.push(new ContainerParser()); + } else if (qName.equals(XmlConstants.XML_PARAMETERS)) { + this.buildersStack.push(new ParametersParser()); + } else if (qName.equals(XmlConstants.XML_POLICIES)) { + this.buildersStack.push(new PoliciesParser()); + } + + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().startElement(uri, localName, qName, attributes); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().characters(ch, start, length); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().endElement(uri, localName, qName); + + ElementParser elementParser = null; + if (qName.equals(XmlConstants.XML_CONTAINER)) { + elementParser = this.buildersStack.pop(); + } else if (qName.equals(XmlConstants.XML_PARAMETERS)) { + elementParser = this.buildersStack.pop(); + } else if (qName.equals(XmlConstants.XML_POLICIES)) { + elementParser = this.buildersStack.pop(); + } + + if (!this.buildersStack.isEmpty() && elementParser != null) + this.buildersStack.peek().notifyChild(elementParser); + } + + public class ContainerParser extends ElementParserAdapter { + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + + private String currentElement; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (qName.equals(XmlConstants.XML_CONTAINER)) { + this.currentElement = qName; + } else if (qName.equals(XmlConstants.XML_HANDLER_ENCRYPTION)) { + this.currentElement = qName; + String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); + getContainerModel().setEncryptionHandlerClassName(className); + } else if (qName.equals(XmlConstants.XML_HANDLER_PERSISTENCE)) { + this.currentElement = qName; + String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); + getContainerModel().setPersistenceHandlerClassName(className); + } + } + + @Override + public void notifyChild(ElementParser child) { + if (!(child instanceof ParametersParser)) + return; + + ParametersParser parametersChild = (ParametersParser) child; + + if (this.currentElement.equals(XmlConstants.XML_CONTAINER)) { + getContainerModel().setParameterMap(parametersChild.getParameterMap()); + } else if (this.currentElement.equals(XmlConstants.XML_HANDLER_ENCRYPTION)) { + getContainerModel().setEncryptionHandlerParameterMap(parametersChild.getParameterMap()); + } else if (this.currentElement.equals(XmlConstants.XML_HANDLER_PERSISTENCE)) { + getContainerModel().setPersistenceHandlerParameterMap(parametersChild.getParameterMap()); + } + } + } + + class ParametersParser extends ElementParserAdapter { + +// + + private Map parameterMap = new HashMap<>(); + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (qName.equals(XmlConstants.XML_PARAMETER)) { + String key = attributes.getValue(XmlConstants.XML_ATTR_NAME); + String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE); + this.parameterMap.put(key, value); + } + } + + /** + * @return the parameterMap + */ + public Map getParameterMap() { + return this.parameterMap; + } + } + + class PoliciesParser extends ElementParserAdapter { + +// + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (qName.equals(XmlConstants.XML_POLICY)) { + String policyName = attributes.getValue(XmlConstants.XML_ATTR_NAME); + String policyClassName = attributes.getValue(XmlConstants.XML_ATTR_CLASS); + + getContainerModel().addPolicy(policyName, policyClassName); + } + } + } +} \ No newline at end of file diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeRolesDomWriter.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeRolesDomWriter.java new file mode 100644 index 000000000..f973f7cda --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeRolesDomWriter.java @@ -0,0 +1,98 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.io.File; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.internal.Role; +import li.strolch.utils.helper.XmlHelper; + +/** + * @author Robert von Burg + */ +public class PrivilegeRolesDomWriter { + + private List roles; + private File modelFile; + + /** + * @param users + * @param roles + * @param modelFile + */ + public PrivilegeRolesDomWriter(List roles, File modelFile) { + this.roles = roles; + this.modelFile = modelFile; + } + + public void write() { + + // create document root + Document doc = XmlHelper.createDocument(); + Element rootElement = doc.createElement(XmlConstants.XML_ROLES); + doc.appendChild(rootElement); + + this.roles.stream().sorted((r1, r2) -> r1.getName().compareTo(r2.getName())).forEach(role -> { + + // create the role element + Element roleElement = doc.createElement(XmlConstants.XML_ROLE); + rootElement.appendChild(roleElement); + + roleElement.setAttribute(XmlConstants.XML_ATTR_NAME, role.getName()); + + for (String privilegeName : role.getPrivilegeNames()) { + IPrivilege privilege = role.getPrivilege(privilegeName); + + // create the privilege element + Element privilegeElement = doc.createElement(XmlConstants.XML_PRIVILEGE); + roleElement.appendChild(privilegeElement); + + privilegeElement.setAttribute(XmlConstants.XML_ATTR_NAME, privilege.getName()); + privilegeElement.setAttribute(XmlConstants.XML_ATTR_POLICY, privilege.getPolicy()); + + // add the all allowed element + if (privilege.isAllAllowed()) { + Element allAllowedElement = doc.createElement(XmlConstants.XML_ALL_ALLOWED); + allAllowedElement.setTextContent(Boolean.toString(privilege.isAllAllowed())); + privilegeElement.appendChild(allAllowedElement); + } + + // add all the deny values + for (String denyValue : privilege.getDenyList()) { + Element denyValueElement = doc.createElement(XmlConstants.XML_DENY); + denyValueElement.setTextContent(denyValue); + privilegeElement.appendChild(denyValueElement); + } + + // add all the allow values + for (String allowValue : privilege.getAllowList()) { + Element allowValueElement = doc.createElement(XmlConstants.XML_ALLOW); + allowValueElement.setTextContent(allowValue); + privilegeElement.appendChild(allowValueElement); + } + } + }); + + // write the container file to disk + XmlHelper.writeDocument(doc, this.modelFile); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeRolesSaxReader.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeRolesSaxReader.java new file mode 100644 index 000000000..768a3b09a --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeRolesSaxReader.java @@ -0,0 +1,220 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.text.MessageFormat; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.internal.PrivilegeImpl; +import li.strolch.privilege.model.internal.Role; +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +public class PrivilegeRolesSaxReader extends DefaultHandler { + + protected static final Logger logger = LoggerFactory.getLogger(PrivilegeRolesSaxReader.class); + + private Deque buildersStack = new ArrayDeque<>(); + + private List roles; + + public PrivilegeRolesSaxReader() { + this.roles = new ArrayList<>(); + } + + public List getRoles() { + return this.roles; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + if (qName.equals(XmlConstants.XML_ROLE)) { + this.buildersStack.push(new RoleParser()); + } else if (qName.equals(XmlConstants.XML_PROPERTIES)) { + this.buildersStack.push(new PropertyParser()); + } + + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().startElement(uri, localName, qName, attributes); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().characters(ch, start, length); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().endElement(uri, localName, qName); + + ElementParser elementParser = null; + if (qName.equals(XmlConstants.XML_ROLE)) { + elementParser = this.buildersStack.pop(); + } else if (qName.equals(XmlConstants.XML_PROPERTIES)) { + elementParser = this.buildersStack.pop(); + } + + if (!this.buildersStack.isEmpty() && elementParser != null) + this.buildersStack.peek().notifyChild(elementParser); + } + +// +// +// true +// +// +// +// +// true +// +// +// true +// +// + + public class RoleParser extends ElementParserAdapter { + + private StringBuilder text; + + private String roleName; + private String privilegeName; + private String privilegePolicy; + private boolean allAllowed; + private Set denyList; + private Set allowList; + + private Map privileges; + + public RoleParser() { + init(); + } + + private void init() { + this.privileges = new HashMap<>(); + + this.text = null; + + this.roleName = null; + this.privilegeName = null; + this.privilegePolicy = null; + this.allAllowed = false; + this.denyList = new HashSet<>(); + this.allowList = new HashSet<>(); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + + this.text = new StringBuilder(); + + if (qName.equals(XmlConstants.XML_ROLE)) { + this.roleName = attributes.getValue(XmlConstants.XML_ATTR_NAME); + } else if (qName.equals(XmlConstants.XML_PRIVILEGE)) { + this.privilegeName = attributes.getValue(XmlConstants.XML_ATTR_NAME); + this.privilegePolicy = attributes.getValue(XmlConstants.XML_ATTR_POLICY); + } else if (qName.equals(XmlConstants.XML_ALLOW) || qName.equals(XmlConstants.XML_DENY) + || qName.equals(XmlConstants.XML_ALL_ALLOWED)) { + // no-op + } else { + throw new IllegalArgumentException("Unhandled tag " + qName); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (this.text != null) + this.text.append(ch, start, length); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + + if (qName.equals(XmlConstants.XML_ALL_ALLOWED)) { + this.allAllowed = StringHelper.parseBoolean(this.text.toString().trim()); + } else if (qName.equals(XmlConstants.XML_ALLOW)) { + this.allowList.add(this.text.toString().trim()); + } else if (qName.equals(XmlConstants.XML_DENY)) { + this.denyList.add(this.text.toString().trim()); + } else if (qName.equals(XmlConstants.XML_PRIVILEGE)) { + + IPrivilege privilege = new PrivilegeImpl(this.privilegeName, this.privilegePolicy, this.allAllowed, + this.denyList, this.allowList); + this.privileges.put(this.privilegeName, privilege); + + this.privilegeName = null; + this.privilegePolicy = null; + this.allAllowed = false; + this.denyList = new HashSet<>(); + this.allowList = new HashSet<>(); + + } else if (qName.equals(XmlConstants.XML_ROLE)) { + + Role role = new Role(this.roleName, this.privileges); + + getRoles().add(role); + logger.info(MessageFormat.format("New Role: {0}", role)); //$NON-NLS-1$ + init(); + } + } + } + + class PropertyParser extends ElementParserAdapter { + +// + + public Map parameterMap = new HashMap<>(); + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (qName.equals(XmlConstants.XML_PROPERTY)) { + String key = attributes.getValue(XmlConstants.XML_ATTR_NAME); + String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE); + this.parameterMap.put(key, value); + } else if (qName.equals(XmlConstants.XML_PROPERTIES)) { + // NO-OP + } else { + throw new IllegalArgumentException("Unhandled tag " + qName); + } + } + + public Map getParameterMap() { + return this.parameterMap; + } + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeUsersDomWriter.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeUsersDomWriter.java new file mode 100644 index 000000000..dec448fce --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeUsersDomWriter.java @@ -0,0 +1,114 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.io.File; +import java.util.List; +import java.util.Map.Entry; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.internal.User; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.helper.XmlHelper; + +/** + * @author Robert von Burg + */ +public class PrivilegeUsersDomWriter { + + private List users; + private File modelFile; + + /** + * @param users + * @param modelFile + */ + public PrivilegeUsersDomWriter(List users, File modelFile) { + this.users = users; + this.modelFile = modelFile; + } + + public void write() { + + // create document root + Document doc = XmlHelper.createDocument(); + Element rootElement = doc.createElement(XmlConstants.XML_USERS); + doc.appendChild(rootElement); + + this.users.stream().sorted((u1, u2) -> u1.getUserId().compareTo(u2.getUserId())).forEach(user -> { + + // create the user element + Element userElement = doc.createElement(XmlConstants.XML_USER); + rootElement.appendChild(userElement); + + userElement.setAttribute(XmlConstants.XML_ATTR_USER_ID, user.getUserId()); + userElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, user.getUsername()); + if (StringHelper.isNotEmpty(user.getPassword())) + userElement.setAttribute(XmlConstants.XML_ATTR_PASSWORD, user.getPassword()); + + // add first name element + if (StringHelper.isNotEmpty(user.getFirstname())) { + Element firstnameElement = doc.createElement(XmlConstants.XML_FIRSTNAME); + firstnameElement.setTextContent(user.getFirstname()); + userElement.appendChild(firstnameElement); + } + + // add last name element + if (StringHelper.isNotEmpty(user.getLastname())) { + Element lastnameElement = doc.createElement(XmlConstants.XML_LASTNAME); + lastnameElement.setTextContent(user.getLastname()); + userElement.appendChild(lastnameElement); + } + + // add state element + Element stateElement = doc.createElement(XmlConstants.XML_STATE); + stateElement.setTextContent(user.getUserState().toString()); + userElement.appendChild(stateElement); + + // add locale element + Element localeElement = doc.createElement(XmlConstants.XML_LOCALE); + localeElement.setTextContent(user.getLocale().toString()); + userElement.appendChild(localeElement); + + // add all the role elements + Element rolesElement = doc.createElement(XmlConstants.XML_ROLES); + userElement.appendChild(rolesElement); + for (String roleName : user.getRoles()) { + Element roleElement = doc.createElement(XmlConstants.XML_ROLE); + roleElement.setTextContent(roleName); + rolesElement.appendChild(roleElement); + } + + // add the parameters + if (!user.getProperties().isEmpty()) { + Element parametersElement = doc.createElement(XmlConstants.XML_PROPERTIES); + userElement.appendChild(parametersElement); + for (Entry entry : user.getProperties().entrySet()) { + Element paramElement = doc.createElement(XmlConstants.XML_PROPERTY); + paramElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey()); + paramElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue()); + parametersElement.appendChild(paramElement); + } + } + }); + + // write the container file to disk + XmlHelper.writeDocument(doc, this.modelFile); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeUsersSaxReader.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeUsersSaxReader.java new file mode 100644 index 000000000..e79efe676 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/xml/PrivilegeUsersSaxReader.java @@ -0,0 +1,209 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.xml; + +import java.text.MessageFormat; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.privilege.helper.XmlConstants; +import li.strolch.privilege.model.UserState; +import li.strolch.privilege.model.internal.User; + +/** + * @author Robert von Burg + */ +public class PrivilegeUsersSaxReader extends DefaultHandler { + + protected static final Logger logger = LoggerFactory.getLogger(PrivilegeUsersSaxReader.class); + + private Deque buildersStack = new ArrayDeque<>(); + + private List users; + + public PrivilegeUsersSaxReader() { + this.users = new ArrayList<>(); + } + + /** + * @return the users + */ + public List getUsers() { + return this.users; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if (qName.equals(XmlConstants.XML_USER)) { + this.buildersStack.push(new UserParser()); + } else if (qName.equals(XmlConstants.XML_PROPERTIES)) { + this.buildersStack.push(new PropertyParser()); + } + + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().startElement(uri, localName, qName, attributes); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().characters(ch, start, length); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + + if (!this.buildersStack.isEmpty()) + this.buildersStack.peek().endElement(uri, localName, qName); + + ElementParser elementParser = null; + if (qName.equals(XmlConstants.XML_USER)) { + elementParser = this.buildersStack.pop(); + } else if (qName.equals(XmlConstants.XML_PROPERTIES)) { + elementParser = this.buildersStack.pop(); + } + + if (!this.buildersStack.isEmpty() && elementParser != null) + this.buildersStack.peek().notifyChild(elementParser); + } + +// +// Application +// Administrator +// ENABLED +// en_GB +// +// PrivilegeAdmin +// AppUser +// +// +// +// +// +// + + public class UserParser extends ElementParserAdapter { + + StringBuilder text; + + String userId; + String username; + String password; + String firstName; + String lastname; + UserState userState; + Locale locale; + Set userRoles; + Map parameters; + + public UserParser() { + this.userRoles = new HashSet<>(); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + + this.text = new StringBuilder(); + + if (qName.equals(XmlConstants.XML_USER)) { + this.userId = attributes.getValue(XmlConstants.XML_ATTR_USER_ID); + this.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME); + this.password = attributes.getValue(XmlConstants.XML_ATTR_PASSWORD); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + this.text.append(ch, start, length); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + + if (qName.equals(XmlConstants.XML_FIRSTNAME)) { + this.firstName = this.text.toString().trim(); + } else if (qName.equals(XmlConstants.XML_LASTNAME)) { + this.lastname = this.text.toString().trim(); + } else if (qName.equals(XmlConstants.XML_STATE)) { + this.userState = UserState.valueOf(this.text.toString().trim()); + } else if (qName.equals(XmlConstants.XML_LOCALE)) { + this.locale = new Locale(this.text.toString().trim()); + } else if (qName.equals(XmlConstants.XML_ROLE)) { + this.userRoles.add(this.text.toString().trim()); + } else if (qName.equals(XmlConstants.XML_ROLES)) { + // NO-OP + } else if (qName.equals(XmlConstants.XML_PARAMETER)) { + // NO-OP + } else if (qName.equals(XmlConstants.XML_PARAMETERS)) { + // NO-OP + } else if (qName.equals(XmlConstants.XML_USER)) { + + User user = new User(this.userId, this.username, this.password, this.firstName, this.lastname, + this.userState, this.userRoles, this.locale, this.parameters); + logger.info(MessageFormat.format("New User: {0}", user)); //$NON-NLS-1$ + getUsers().add(user); + } else { + throw new IllegalArgumentException("Unhandled tag " + qName); + } + } + + @Override + public void notifyChild(ElementParser child) { + if (child instanceof PropertyParser) { + this.parameters = ((PropertyParser) child).parameterMap; + } + } + } + + class PropertyParser extends ElementParserAdapter { + +// + + public Map parameterMap = new HashMap<>(); + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (qName.equals(XmlConstants.XML_PROPERTY)) { + String key = attributes.getValue(XmlConstants.XML_ATTR_NAME); + String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE); + this.parameterMap.put(key, value); + } else if (qName.equals(XmlConstants.XML_PROPERTIES)) { + // NO-OP + } else { + throw new IllegalArgumentException("Unhandled tag " + qName); + } + } + + public Map getParameterMap() { + return this.parameterMap; + } + } +} diff --git a/li.strolch.privilege/src/main/resources/Privilege.xsd b/li.strolch.privilege/src/main/resources/Privilege.xsd new file mode 100644 index 000000000..2fbcbdb1d --- /dev/null +++ b/li.strolch.privilege/src/main/resources/Privilege.xsd @@ -0,0 +1,83 @@ + + + + + + Copyright 2013 Robert von Burg <eitch@eitchnet.ch> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/li.strolch.privilege/src/main/resources/PrivilegeMessages.properties b/li.strolch.privilege/src/main/resources/PrivilegeMessages.properties new file mode 100644 index 000000000..a92f0f135 --- /dev/null +++ b/li.strolch.privilege/src/main/resources/PrivilegeMessages.properties @@ -0,0 +1,14 @@ +Privilege.accessdenied.noprivilege=User {0} does not have the privilege {1} needed for Restrictable {2} +Privilege.illegalArgument.nonstring=\ {0} has returned a non-string privilege value\! +Privilege.illegalArgument.nonrole=\ {0} did not return a Role privilege value\! +Privilege.illegalArgument.noncertificate=\ {0} did not return a Certificate privilege value\! +Privilege.illegalArgument.nonuser=\ {0} did not return a User privilege value\! +Privilege.illegalArgument.privilegeNameMismatch=The passed privilege has the name {0} but the restrictable is referencing privilege {1} +Privilege.illegalArgument.nontuple=\ {0} did not return a Tuple privilege value\! +Privilege.privilegeNameEmpty=The PrivilegeName for the Restrictable is null or empty: {0} +Privilege.privilegeNull=Privilege may not be null\! +Privilege.restrictableNull=Restrictable may not be null\! +Privilege.noprivilege=No Privilege exists with name {0} +Privilege.noprivilege.user=User {0} does not have the privilege {1} +Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1} +Privilege.userAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1} diff --git a/li.strolch.privilege/src/main/resources/PrivilegeModel.xsd b/li.strolch.privilege/src/main/resources/PrivilegeModel.xsd new file mode 100644 index 000000000..d2f82d897 --- /dev/null +++ b/li.strolch.privilege/src/main/resources/PrivilegeModel.xsd @@ -0,0 +1,98 @@ + + + + + +Copyright 2013 Robert von Burg <eitch@eitchnet.ch> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/AbstractPrivilegeTest.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/AbstractPrivilegeTest.java new file mode 100644 index 000000000..af4af356e --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/AbstractPrivilegeTest.java @@ -0,0 +1,116 @@ +package li.strolch.privilege.test; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.nio.file.Files; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.helper.PrivilegeInitializationHelper; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.utils.helper.FileHelper; + +public class AbstractPrivilegeTest { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractPrivilegeTest.class); + + protected PrivilegeHandler privilegeHandler; + protected PrivilegeContext ctx; + + protected void login(String username, byte[] password) { + Certificate certificate = privilegeHandler.authenticate(username, password); + assertTrue("Certificate is null!", certificate != null); + PrivilegeContext privilegeContext = privilegeHandler.getPrivilegeContext(certificate); + this.ctx = privilegeContext; + } + + protected void logout() { + if (this.ctx != null) { + try { + PrivilegeContext privilegeContext = this.ctx; + this.ctx = null; + privilegeHandler.invalidateSession(privilegeContext.getCertificate()); + } catch (PrivilegeException e) { + String msg = "There is no PrivilegeContext currently bound to the ThreadLocal!"; + if (!e.getMessage().equals(msg)) + throw e; + } + } + } + + protected static void prepareConfigs(String dst, String configFilename, String usersFilename, + String rolesFilename) { + try { + String pwd = System.getProperty("user.dir"); + + File configPath = new File(pwd, "config"); + + File privilegeConfigFile = new File(configPath, configFilename); + File privilegeUsersFile = new File(configPath, usersFilename); + File privilegeRolesFile = new File(configPath, rolesFilename); + + File targetPath = new File(pwd, "target/" + dst); + if (!targetPath.mkdirs()) + throw new RuntimeException("Could not create parent " + targetPath); + + File dstConfig = new File(targetPath, configFilename); + File dstUsers = new File(targetPath, usersFilename); + File dstRoles = new File(targetPath, rolesFilename); + + // write config + String config = new String(Files.readAllBytes(privilegeConfigFile.toPath()), "UTF-8"); + config = config.replace("${target}", dst); + Files.write(dstConfig.toPath(), config.getBytes("UTF-8")); + + // copy model + Files.copy(privilegeUsersFile.toPath(), dstUsers.toPath()); + Files.copy(privilegeRolesFile.toPath(), dstRoles.toPath()); + + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException("Initialization failed", e); + } + } + + protected static void removeConfigs(String dst) { + try { + String pwd = System.getProperty("user.dir"); + File targetPath = new File(pwd, "target"); + targetPath = new File(targetPath, dst); + if (targetPath.exists() && !FileHelper.deleteFile(targetPath, true)) { + throw new RuntimeException( + "Tmp configuration still exists and can not be deleted at " + targetPath.getAbsolutePath()); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException("Initialization failed", e); + } + } + + protected static File getPrivilegeConfigFile(String dst, String configFilename) { + try { + String pwd = System.getProperty("user.dir"); + File targetPath = new File(pwd, "target"); + targetPath = new File(targetPath, dst); + return new File(targetPath, configFilename); + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException("Initialization failed", e); + } + } + + protected void initialize(String dst, String configFilename) { + try { + File privilegeConfigFile = getPrivilegeConfigFile(dst, configFilename); + this.privilegeHandler = PrivilegeInitializationHelper.initializeFromXml(privilegeConfigFile); + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException("Initialization failed", e); + } + } +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PersistSessionsTest.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PersistSessionsTest.java new file mode 100644 index 000000000..e79ddbb57 --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PersistSessionsTest.java @@ -0,0 +1,48 @@ +package li.strolch.privilege.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PersistSessionsTest extends AbstractPrivilegeTest { + + @BeforeClass + public static void init() throws Exception { + removeConfigs(PersistSessionsTest.class.getSimpleName()); + prepareConfigs(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml", + "PrivilegeRoles.xml"); + } + + @AfterClass + public static void destroy() throws Exception { + removeConfigs(PersistSessionsTest.class.getSimpleName()); + } + + @Before + public void setup() throws Exception { + initialize(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml"); + } + + @Test + public void shouldPersistAndReloadSessions() { + + // assert no sessions file + File sessionsFile = new File("target/PersistSessionsTest/sessions.dat"); + assertFalse("Sessions File should no yet exist", sessionsFile.exists()); + + // login and assert sessions file was written + login("admin", "admin".getBytes()); + this.privilegeHandler.isCertificateValid(ctx.getCertificate()); + assertTrue("Sessions File should have been created!", sessionsFile.isFile()); + + // re-initialize and assert still logged in + initialize(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml"); + this.privilegeHandler.isCertificateValid(ctx.getCertificate()); + } +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PrivilegeConflictMergeTest.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PrivilegeConflictMergeTest.java new file mode 100644 index 000000000..8943c1c5f --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PrivilegeConflictMergeTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import li.strolch.privilege.model.IPrivilege; + +/** + * @author Robert von Burg + */ +public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest { + + @BeforeClass + public static void init() throws Exception { + removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName()); + prepareConfigs(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml", + "PrivilegeUsersMerge.xml", "PrivilegeRolesMerge.xml"); + } + + @AfterClass + public static void destroy() throws Exception { + removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName()); + } + + @Before + public void setup() throws Exception { + initialize(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml"); + } + + @Test + public void shouldMergePrivileges1() { + try { + login("userA", "admin".getBytes()); + IPrivilege privilege = this.ctx.getPrivilege("Foo"); + assertTrue(privilege.isAllAllowed()); + assertTrue(privilege.getAllowList().isEmpty()); + assertTrue(privilege.getDenyList().isEmpty()); + + } finally { + logout(); + } + } + + @Test + public void shouldMergePrivileges2() { + try { + login("userB", "admin".getBytes()); + IPrivilege privilege = this.ctx.getPrivilege("Bar"); + assertFalse(privilege.isAllAllowed()); + assertEquals(2, privilege.getAllowList().size()); + assertEquals(2, privilege.getDenyList().size()); + } finally { + logout(); + } + } +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PrivilegeTest.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PrivilegeTest.java new file mode 100644 index 000000000..c0a956842 --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/PrivilegeTest.java @@ -0,0 +1,755 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.i18n.PrivilegeMessages; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.Restrictable; +import li.strolch.privilege.model.RoleRep; +import li.strolch.privilege.model.UserRep; +import li.strolch.privilege.model.UserState; +import li.strolch.privilege.test.model.TestRestrictable; +import li.strolch.privilege.test.model.TestSystemUserAction; +import li.strolch.privilege.test.model.TestSystemUserActionDeny; +import li.strolch.utils.helper.ArraysHelper; + +/** + * JUnit for performing Privilege tests. This JUnit is by no means complete, but checks the bare minimum.br /> + * + * TODO add more tests, especially with deny and allow lists + * + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class PrivilegeTest extends AbstractPrivilegeTest { + + private static final String ROLE_PRIVILEGE_ADMIN = "PrivilegeAdmin"; + private static final String PRIVILEGE_USER_ACCESS = "UserAccessPrivilege"; + private static final String ADMIN = "admin"; + private static final byte[] PASS_ADMIN = "admin".getBytes(); + private static final String BOB = "bob"; + private static final String TED = "ted"; + private static final String SYSTEM_USER_ADMIN = "system_admin"; + private static final String SYSTEM_USER_ADMIN2 = "system_admin2"; + private static final byte[] PASS_BOB = "admin1".getBytes(); + private static final String ROLE_APP_USER = "AppUser"; + private static final String ROLE_MY = "MyRole"; + private static final String ROLE_MY2 = "MyRole2"; + private static final String ROLE_CHANGE_PW = "changePw"; + private static final String ROLE_TEMP = "temp"; + private static final String ROLE_USER = "user"; + private static final byte[] PASS_DEF = "def".getBytes(); + private static final byte[] PASS_BAD = "123".getBytes(); + private static final byte[] PASS_TED = "12345".getBytes(); + + private static final Logger logger = LoggerFactory.getLogger(PrivilegeTest.class); + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void init() throws Exception { + removeConfigs(PrivilegeTest.class.getSimpleName()); + prepareConfigs(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml", + "PrivilegeRoles.xml"); + } + + @AfterClass + public static void destroy() throws Exception { + removeConfigs(PrivilegeTest.class.getSimpleName()); + } + + @Before + public void setup() throws Exception { + initialize(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml"); + } + + @Test + public void testAuthenticationOk() throws Exception { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + } finally { + logout(); + } + } + + public void testFailAuthenticationNOk() throws Exception { + this.exception.expect(AccessDeniedException.class); + this.exception.expectMessage("blabla"); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_BAD)); + } finally { + logout(); + } + } + + public void testFailAuthenticationPWNull() throws Exception { + this.exception.expect(PrivilegeException.class); + this.exception.expectMessage("blabla"); + try { + login(ADMIN, null); + } finally { + logout(); + } + } + + @Test + public void testAddRoleTemp() throws Exception { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + RoleRep roleRep = new RoleRep(ROLE_TEMP, new ArrayList<>()); + + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRole(certificate, roleRep); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + @Test + public void testPerformRestrictableAsAdmin() throws Exception { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + // see if admin can perform restrictable + Restrictable restrictable = new TestRestrictable(); + this.ctx.validateAction(restrictable); + + } finally { + logout(); + } + } + + /** + * Tests if an action can be performed as a system user + */ + @Test + public void testPerformSystemRestrictable() throws Exception { + + // create the action to be performed as a system user and then perform the action + TestSystemUserAction action = new TestSystemUserAction(); + privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action); + } + + /** + * Checks that the system user can not perform a valid action, but illegal privilege + */ + @Test + public void testPerformSystemRestrictableFailPrivilege() throws Exception { + this.exception.expect(PrivilegeException.class); + this.exception.expectMessage( + "User system_admin does not have the privilege li.strolch.privilege.handler.SystemUserAction"); + try { + // create the action to be performed as a system user + TestSystemUserActionDeny action = new TestSystemUserActionDeny(); + + // and then perform the action + privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action); + } finally { + logout(); + } + } + + /** + * Checks that the system user can not perform a valid action, but illegal privilege + */ + @Test + public void testPerformSystemRestrictableFailNoAdditionalPrivilege() throws Exception { + this.exception.expect(PrivilegeException.class); + this.exception.expectMessage( + "User system_admin2 does not have the privilege li.strolch.privilege.handler.SystemUserAction needed for Restrictable li.strolch.privilege.test.model.TestSystemUserActionDeny"); + try { + // create the action to be performed as a system user + TestSystemUserActionDeny action = new TestSystemUserActionDeny(); + + // and then perform the action + privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN2, action); + } finally { + logout(); + } + } + + /** + * System user may not login + */ + @Test + public void testLoginSystemUser() throws Exception { + this.exception.expect(AccessDeniedException.class); + this.exception.expectMessage("User system_admin is a system user and may not login!"); + try { + login(SYSTEM_USER_ADMIN, SYSTEM_USER_ADMIN.getBytes()); + } finally { + logout(); + } + } + + @Test + public void testPrivilegeContext() { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Restrictable restrictable = new TestRestrictable(); + this.ctx.validateAction(restrictable); + } finally { + logout(); + } + } + + @Test + public void shouldUpdateAdmin() { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + Certificate certificate = this.ctx.getCertificate(); + + // validate name is not yet set + UserRep user = privilegeHandler.getUser(certificate, ADMIN); + assertNotEquals("The", user.getFirstname()); + assertNotEquals("Admin", user.getLastname()); + + // let's add a new user bob + UserRep userRep = new UserRep(null, ADMIN, "The", "Admin", null, null, null, null); + privilegeHandler.updateUser(certificate, userRep); + + user = privilegeHandler.getUser(certificate, ADMIN); + assertEquals("The", user.getFirstname()); + assertEquals("Admin", user.getLastname()); + + } finally { + logout(); + } + } + + @Test + public void shouldFailUpdateInexistantUser() { + exception.expect(PrivilegeException.class); + exception.expectMessage("User bob does not exist"); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + Certificate certificate = this.ctx.getCertificate(); + + // let's add a new user bob + UserRep userRep = new UserRep(null, BOB, null, null, null, null, null, null); + privilegeHandler.updateUser(certificate, userRep); + } finally { + logout(); + } + } + + @Test + public void shouldFailUpdateAdminNoChanges() { + exception.expect(PrivilegeException.class); + exception.expectMessage("All updateable fields are empty for update of user admin"); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + Certificate certificate = this.ctx.getCertificate(); + + // let's add a new user bob + UserRep userRep = new UserRep(null, ADMIN, null, null, null, null, null, null); + privilegeHandler.updateUser(certificate, userRep); + } finally { + logout(); + } + } + + @Test + public void shouldQueryUsers() { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + Certificate certificate = this.ctx.getCertificate(); + + UserRep selectorRep = new UserRep(null, ADMIN, null, null, null, null, null, null); + List users = privilegeHandler.queryUsers(certificate, selectorRep); + assertEquals(1, users.size()); + assertEquals(ADMIN, users.get(0).getUsername()); + + } finally { + logout(); + } + } + + @Test + public void shouldQueryUsersByRoles() { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + Certificate certificate = this.ctx.getCertificate(); + + UserRep selectorRep = new UserRep(null, null, null, null, null, + new HashSet<>(Arrays.asList("PrivilegeAdmin")), null, null); + List users = privilegeHandler.queryUsers(certificate, selectorRep); + assertEquals(1, users.size()); + assertEquals(ADMIN, users.get(0).getUsername()); + + } finally { + logout(); + } + } + + @Test + public void shouldQueryUsersByRoles2() { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + Certificate certificate = this.ctx.getCertificate(); + + UserRep selectorRep = new UserRep(null, null, null, null, null, new HashSet<>(Arrays.asList(ROLE_TEMP)), + null, null); + List users = privilegeHandler.queryUsers(certificate, selectorRep); + assertEquals(0, users.size()); + + } finally { + logout(); + } + } + + @Test + public void shouldDetectPrivilegeConflict1() { + exception.expect(PrivilegeException.class); + exception.expectMessage("User admin has conflicts for privilege "); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = this.ctx.getCertificate(); + PrivilegeRep privilegeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_ACTION, "DefaultPrivilege", true, + Collections.emptySet(), Collections.emptySet()); + privilegeHandler.addOrReplacePrivilegeOnRole(certificate, ROLE_APP_USER, privilegeRep); + } finally { + logout(); + } + } + + @Test + public void shouldDetectPrivilegeConflict2() { + exception.expect(PrivilegeException.class); + exception.expectMessage("User admin has conflicts for privilege "); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY); + privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY2); + } finally { + logout(); + } + } + + /** + * This test performs multiple tests which are dependent on each other as the following is done: + *
    + *
  • add user bob
  • + *
  • fail to auth as bob as user is not enabled
  • + *
  • enable bob
  • + *
  • fail to auth as bot as bob has no role
  • + *
  • add role user to bob
  • + *
  • auth as bob
  • + *
  • fail to add user ted as bob as bob is not admin
  • + *
  • add admin role to bob
  • + *
  • add user ted as bob
  • + *
  • fail to auth as ted as ted has no password
  • + *
  • set ted's password as bob
  • + *
  • ted changes own password
  • + *
  • auth as ted
  • + *
  • fail to perform restrictable as bob as no app role
  • + *
  • add app role to bob
  • + *
  • perform restrictable as bob
  • + *
+ */ + @Test + public void testUserStory() throws Exception { + + addBobAsAdmin(); + failAuthAsBobNotEnabled(); + enableBob(); + addRoleUser(); + addRoleUserToBob(); + authAsBob(); + failAddTedAsBobNotAdmin(); + addRoleAdminToBob(); + addTedAsBob(); + failAuthAsTedNoPass(); + setPassForTedAsBob(); + failSetSystemStateTed(); + failTedChangesPwAndLocale(); + addChangePwRoleToTed(); + tedChangesOwnPassAndLocale(); + failTedChangesOtherPwStateAndLocale(); + authAsTed(); + failPerformRestrictableAsBobNoRoleApp(); + addRoleAppToBob(); + performRestrictableAsBob(); + } + + private void failSetSystemStateTed() { + try { + // testEnableUserBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + Certificate certificate = this.ctx.getCertificate(); + + try { + privilegeHandler.setUserState(certificate, TED, UserState.SYSTEM); + fail("Should not be able to set user state to SYSTEM"); + } catch (AccessDeniedException e) { + // ok + } + + } finally { + logout(); + } + } + + private void failTedChangesOtherPwStateAndLocale() { + try { + // testTedChangesOwnPwd + login(TED, ArraysHelper.copyOf(PASS_TED)); + Certificate certificate = this.ctx.getCertificate(); + + try { + privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_TED)); + fail("Should not be able to set password of other user, as missing privilege"); + } catch (AccessDeniedException e) { + // ok + } + + try { + privilegeHandler.setUserLocale(certificate, BOB, Locale.FRENCH); + fail("Should not be able to set locale of other user, as missing privilege"); + } catch (AccessDeniedException e) { + // ok + } + + try { + privilegeHandler.setUserState(certificate, BOB, UserState.DISABLED); + fail("Should not be able to set state of other user, as missing privilege"); + } catch (AccessDeniedException e) { + // ok + } + + } finally { + logout(); + } + } + + private void failTedChangesPwAndLocale() { + try { + // testTedChangesOwnPwd + login(TED, ArraysHelper.copyOf(PASS_DEF)); + Certificate certificate = this.ctx.getCertificate(); + + try { + privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED)); + fail("Should not be able to set password, as missing privilege"); + } catch (AccessDeniedException e) { + // ok + } + + try { + privilegeHandler.setUserLocale(certificate, TED, Locale.FRENCH); + fail("Should not be able to set locale, as missing privilege"); + } catch (AccessDeniedException e) { + // ok + } + + try { + privilegeHandler.setUserState(certificate, TED, UserState.ENABLED); + fail("Should not be able to set state, as missing privilege"); + } catch (AccessDeniedException e) { + // ok + } + + } finally { + logout(); + } + } + + private void addChangePwRoleToTed() { + try { + // add role user + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + PrivilegeRep passwordRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD, + PRIVILEGE_USER_ACCESS, false, Collections.emptySet(), Collections.emptySet()); + PrivilegeRep localeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_LOCALE, PRIVILEGE_USER_ACCESS, + false, Collections.emptySet(), Collections.emptySet()); + + RoleRep roleRep = new RoleRep(ROLE_CHANGE_PW, Arrays.asList(passwordRep, localeRep)); + + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRole(certificate, roleRep); + privilegeHandler.addRoleToUser(certificate, TED, ROLE_CHANGE_PW); + logger.info("Added " + ROLE_CHANGE_PW + " to " + TED); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void performRestrictableAsBob() { + try { + // testPerformRestrictableAsBob + // Tests if the user bob, who now has AppUser role can perform restrictable + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // see if bob can perform restrictable + Restrictable restrictable = new TestRestrictable(); + this.ctx.validateAction(restrictable); + } finally { + logout(); + } + } + + private void addRoleAppToBob() { + try { + // testAddAppRoleToBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRoleToUser(certificate, BOB, ROLE_APP_USER); + logger.info("Added " + ROLE_APP_USER + " to " + BOB); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void failPerformRestrictableAsBobNoRoleApp() { + try { + // testFailPerformRestrictableAsBob + // Tests if the user bob, who does not have AppUser role can perform restrictable + // this will fail as bob does not have role app + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // see if bob can perform restrictable + Restrictable restrictable = new TestRestrictable(); + this.ctx.validateAction(restrictable); + fail("Should fail as bob does not have role app"); + } catch (AccessDeniedException e) { + String msg = "User bob does not have the privilege li.strolch.privilege.test.model.TestRestrictable needed for Restrictable li.strolch.privilege.test.model.TestRestrictable"; + assertEquals(msg, e.getLocalizedMessage()); + } finally { + logout(); + } + } + + private void authAsTed() { + try { + // testAuthAsTed + login(TED, ArraysHelper.copyOf(PASS_TED)); + } finally { + logout(); + } + } + + private void tedChangesOwnPassAndLocale() { + try { + // testTedChangesOwnPwd + login(TED, ArraysHelper.copyOf(PASS_DEF)); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED)); + privilegeHandler.setUserLocale(certificate, TED, Locale.FRENCH); + } finally { + logout(); + } + } + + private void setPassForTedAsBob() { + try { + // testSetTedPwdAsBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // set ted's password to default + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_DEF)); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void failAuthAsTedNoPass() { + try { + // testFailAuthAsTedNoPass + // Will fail because user ted has no password + login(TED, ArraysHelper.copyOf(PASS_TED)); + fail("User Ted may not authenticate because the user has no password!"); + } catch (PrivilegeException e) { + String msg = "User ted has no password and may not login!"; + assertEquals(msg, e.getMessage()); + } finally { + logout(); + } + } + + private void addTedAsBob() { + try { + UserRep userRep; + // testAddUserTedAsBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // let's add a new user ted + HashSet roles = new HashSet<>(); + roles.add(ROLE_USER); + userRep = new UserRep(null, TED, "Ted", "Newman", UserState.ENABLED, roles, null, + new HashMap()); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addUser(certificate, userRep, null); + logger.info("Added user " + TED); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void addRoleAdminToBob() { + try { + // testAddAdminRoleToBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRoleToUser(certificate, BOB, ROLE_PRIVILEGE_ADMIN); + logger.info("Added " + ROLE_PRIVILEGE_ADMIN + " to " + ADMIN); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void failAddTedAsBobNotAdmin() { + Certificate certificate = null; + try { + UserRep userRep; + // testFailAddUserTedAsBob + // Will fail because user bob does not have admin rights + // auth as Bob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // let's add a new user Ted + userRep = new UserRep("1", TED, "Ted", "And then Some", UserState.NEW, new HashSet(), null, + new HashMap()); + certificate = this.ctx.getCertificate(); + privilegeHandler.addUser(certificate, userRep, null); + fail("User bob may not add a user as bob does not have admin rights!"); + } catch (PrivilegeException e) { + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), //$NON-NLS-1$ + BOB, PrivilegeHandler.PRIVILEGE_ADD_USER); + assertEquals(msg, e.getMessage()); + } finally { + logout(); + } + } + + private void authAsBob() { + try { + // testAuthAsBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + } finally { + logout(); + } + } + + private void addRoleUserToBob() { + try { + // testAddRoleUserToBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRoleToUser(certificate, BOB, ROLE_USER); + privilegeHandler.persist(certificate); + logout(); + } finally { + logout(); + } + } + + private void addRoleUser() { + try { + // add role user + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + RoleRep roleRep = new RoleRep(ROLE_USER, new ArrayList<>()); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addRole(certificate, roleRep); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void enableBob() { + try { + // testEnableUserBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.setUserState(certificate, BOB, UserState.ENABLED); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } + + private void failAuthAsBobNotEnabled() { + try { + // testFailAuthAsBob + // Will fail because user bob is not yet enabled + privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB)); + fail("User Bob may not authenticate because the user is not yet enabled!"); + } catch (PrivilegeException e) { + String msg = "User bob does not have state ENABLED and can not login!"; + assertEquals(msg, e.getMessage()); + } finally { + logout(); + } + } + + private void addBobAsAdmin() { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + + // let's add a new user bob + UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW, + new HashSet<>(Arrays.asList(ROLE_MY)), null, new HashMap()); + Certificate certificate = this.ctx.getCertificate(); + privilegeHandler.addUser(certificate, userRep, null); + logger.info("Added user " + BOB); + + // set bob's password + privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_BOB)); + logger.info("Set Bob's password"); + privilegeHandler.persist(certificate); + } finally { + logout(); + } + } +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/XmlTest.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/XmlTest.java new file mode 100644 index 000000000..bd274388c --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/XmlTest.java @@ -0,0 +1,454 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.privilege.handler.DefaultEncryptionHandler; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.handler.XmlPersistenceHandler; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.UserState; +import li.strolch.privilege.model.internal.PrivilegeContainerModel; +import li.strolch.privilege.model.internal.PrivilegeImpl; +import li.strolch.privilege.model.internal.Role; +import li.strolch.privilege.model.internal.User; +import li.strolch.privilege.xml.PrivilegeConfigDomWriter; +import li.strolch.privilege.xml.PrivilegeConfigSaxReader; +import li.strolch.privilege.xml.PrivilegeRolesDomWriter; +import li.strolch.privilege.xml.PrivilegeRolesSaxReader; +import li.strolch.privilege.xml.PrivilegeUsersDomWriter; +import li.strolch.privilege.xml.PrivilegeUsersSaxReader; +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.helper.XmlHelper; + +/** + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class XmlTest { + + private static final String TARGET_TEST = "./target/test"; + private static final Logger logger = LoggerFactory.getLogger(XmlTest.class); + + /** + * @throws Exception + * if something goes wrong + */ + @BeforeClass + public static void init() throws Exception { + + cleanUp(); + + File tmpDir = new File("target/test"); + if (tmpDir.exists()) + FileHelper.deleteFile(tmpDir, false); + tmpDir.mkdirs(); + } + + @AfterClass + public static void cleanUp() throws Exception { + + File tmpDir = new File("target/test"); + if (!tmpDir.exists()) + return; + + File tmpFile = new File("target/test/PrivilegeTest.xml"); + if (tmpFile.exists() && !tmpFile.delete()) { + throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath()); + } + + tmpFile = new File("target/test/PrivilegeUsersTest.xml"); + if (tmpFile.exists() && !tmpFile.delete()) { + throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath()); + } + + tmpFile = new File("target/test/PrivilegeRolesTest.xml"); + if (tmpFile.exists() && !tmpFile.delete()) { + throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath()); + } + + // and temporary parent + if (!tmpDir.delete()) { + throw new RuntimeException("Could not remove temporary parent for tmp " + tmpFile); + } + } + + @Test + public void canReadConfig() { + + PrivilegeContainerModel containerModel = new PrivilegeContainerModel(); + PrivilegeConfigSaxReader saxReader = new PrivilegeConfigSaxReader(containerModel); + File xmlFile = new File("config/PrivilegeConfig.xml"); + XmlHelper.parseDocument(xmlFile, saxReader); + logger.info(containerModel.toString()); + + // assert all objects read + assertNotNull(containerModel.getParameterMap()); + assertNotNull(containerModel.getPolicies()); + assertNotNull(containerModel.getEncryptionHandlerClassName()); + assertNotNull(containerModel.getEncryptionHandlerParameterMap()); + assertNotNull(containerModel.getPersistenceHandlerClassName()); + assertNotNull(containerModel.getPersistenceHandlerParameterMap()); + + assertEquals(6, containerModel.getParameterMap().size()); + assertEquals(3, containerModel.getPolicies().size()); + assertEquals(1, containerModel.getEncryptionHandlerParameterMap().size()); + assertEquals(3, containerModel.getPersistenceHandlerParameterMap().size()); + + // TODO extend assertions to actual model + } + + @Test + public void canWriteConfig() { + + Map parameterMap = new HashMap<>(); + Map encryptionHandlerParameterMap = new HashMap<>(); + Map persistenceHandlerParameterMap = new HashMap<>(); + + parameterMap.put("autoPersistOnPasswordChange", "true"); + encryptionHandlerParameterMap.put("hashAlgorithm", "SHA-256"); + persistenceHandlerParameterMap.put("basePath", TARGET_TEST); + persistenceHandlerParameterMap.put("modelXmlFile", "PrivilegeModel.xml"); + + PrivilegeContainerModel containerModel = new PrivilegeContainerModel(); + containerModel.setParameterMap(parameterMap); + containerModel.setEncryptionHandlerClassName(DefaultEncryptionHandler.class.getName()); + containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap); + containerModel.setPersistenceHandlerClassName(XmlPersistenceHandler.class.getName()); + containerModel.setPersistenceHandlerParameterMap(persistenceHandlerParameterMap); + + containerModel.addPolicy("DefaultPrivilege", "li.strolch.privilege.policy.DefaultPrivilege"); + + File configFile = new File("./target/test/PrivilegeTest.xml"); + PrivilegeConfigDomWriter configSaxWriter = new PrivilegeConfigDomWriter(containerModel, configFile); + configSaxWriter.write(); + + String fileHash = StringHelper.getHexString(FileHelper.hashFileSha256(configFile)); + assertEquals("800b8e42e15b6b3bb425fa9c12a011d587d2b12343a1d1371eaa36dc1b2ea5f4", fileHash); + } + + @Test + public void canReadUsers() { + + PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader(); + File xmlFile = new File("config/PrivilegeUsers.xml"); + XmlHelper.parseDocument(xmlFile, xmlHandler); + + List users = xmlHandler.getUsers(); + assertNotNull(users); + + assertEquals(3, users.size()); + + // + // users + // + + // admin + User admin = findUser("admin", users); + assertEquals("1", admin.getUserId()); + assertEquals("admin", admin.getUsername()); + assertEquals("8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918", admin.getPassword()); + assertEquals("Application", admin.getFirstname()); + assertEquals("Administrator", admin.getLastname()); + assertEquals(UserState.ENABLED, admin.getUserState()); + assertEquals("en_gb", admin.getLocale().toString()); + assertThat(admin.getRoles(), containsInAnyOrder("PrivilegeAdmin", "AppUser")); + Map properties = admin.getProperties(); + assertEquals(new HashSet<>(Arrays.asList("organization", "organizationalUnit")), properties.keySet()); + assertEquals("eitchnet.ch", properties.get("organization")); + assertEquals("Development", properties.get("organizationalUnit")); + + // system_admin + User systemAdmin = findUser("system_admin", users); + assertEquals("2", systemAdmin.getUserId()); + assertEquals("system_admin", systemAdmin.getUsername()); + assertEquals(null, systemAdmin.getPassword()); + assertEquals("System User", systemAdmin.getFirstname()); + assertEquals("Administrator", systemAdmin.getLastname()); + assertEquals(UserState.SYSTEM, systemAdmin.getUserState()); + assertEquals("en_gb", systemAdmin.getLocale().toString()); + assertThat(systemAdmin.getRoles(), containsInAnyOrder("system_admin_privileges")); + assertTrue(systemAdmin.getProperties().isEmpty()); + } + + @Test + public void canReadRoles() { + + PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader(); + File xmlFile = new File("config/PrivilegeRoles.xml"); + XmlHelper.parseDocument(xmlFile, xmlHandler); + + List roles = xmlHandler.getRoles(); + assertNotNull(roles); + + assertEquals(6, roles.size()); + + // assert model + + // + // roles + // + + // PrivilegeAdmin + Role privilegeAdmin = findRole("PrivilegeAdmin", roles); + assertEquals("PrivilegeAdmin", privilegeAdmin.getName()); + assertEquals(14, privilegeAdmin.getPrivilegeNames().size()); + IPrivilege privilegeAction = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ACTION); + assertFalse(privilegeAction.isAllAllowed()); + assertEquals(3, privilegeAction.getAllowList().size()); + assertEquals(0, privilegeAction.getDenyList().size()); + assertEquals("DefaultPrivilege", privilegeAction.getPolicy()); + + IPrivilege privilegeAddRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ADD_ROLE); + assertTrue(privilegeAddRole.isAllAllowed()); + assertEquals(0, privilegeAddRole.getAllowList().size()); + assertEquals(0, privilegeAddRole.getDenyList().size()); + + IPrivilege privilegeRemRoleFromUser = privilegeAdmin + .getPrivilege(PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER); + assertTrue(privilegeRemRoleFromUser.isAllAllowed()); + assertEquals(0, privilegeRemRoleFromUser.getAllowList().size()); + assertEquals(0, privilegeRemRoleFromUser.getDenyList().size()); + + // AppUser + Role appUser = findRole("AppUser", roles); + assertEquals("AppUser", appUser.getName()); + assertEquals(new HashSet<>(Arrays.asList("li.strolch.privilege.test.model.TestRestrictable")), + appUser.getPrivilegeNames()); + + IPrivilege testRestrictable = appUser.getPrivilege("li.strolch.privilege.test.model.TestRestrictable"); + assertEquals("li.strolch.privilege.test.model.TestRestrictable", testRestrictable.getName()); + assertEquals("DefaultPrivilege", testRestrictable.getPolicy()); + assertTrue(testRestrictable.isAllAllowed()); + assertEquals(0, testRestrictable.getAllowList().size()); + assertEquals(0, testRestrictable.getDenyList().size()); + + // system_admin_privileges + Role systemAdminPrivileges = findRole("system_admin_privileges", roles); + assertEquals("system_admin_privileges", systemAdminPrivileges.getName()); + assertEquals(2, systemAdminPrivileges.getPrivilegeNames().size()); + assertThat(systemAdminPrivileges.getPrivilegeNames(), + containsInAnyOrder("li.strolch.privilege.handler.SystemUserAction", + "li.strolch.privilege.test.model.TestSystemRestrictable")); + + IPrivilege testSystemUserAction = systemAdminPrivileges + .getPrivilege("li.strolch.privilege.handler.SystemUserAction"); + assertEquals("li.strolch.privilege.handler.SystemUserAction", testSystemUserAction.getName()); + assertEquals("DefaultPrivilege", testSystemUserAction.getPolicy()); + assertFalse(testSystemUserAction.isAllAllowed()); + assertEquals(1, testSystemUserAction.getAllowList().size()); + assertEquals(1, testSystemUserAction.getDenyList().size()); + + IPrivilege testSystemRestrictable = systemAdminPrivileges + .getPrivilege("li.strolch.privilege.test.model.TestSystemRestrictable"); + assertEquals("li.strolch.privilege.test.model.TestSystemRestrictable", testSystemRestrictable.getName()); + assertEquals("DefaultPrivilege", testSystemRestrictable.getPolicy()); + assertTrue(testSystemRestrictable.isAllAllowed()); + assertEquals(0, testSystemRestrictable.getAllowList().size()); + assertEquals(0, testSystemRestrictable.getDenyList().size()); + + // restrictedRole + Role restrictedRole = findRole("restrictedRole", roles); + assertEquals("restrictedRole", restrictedRole.getName()); + assertEquals(1, restrictedRole.getPrivilegeNames().size()); + assertThat(restrictedRole.getPrivilegeNames(), + containsInAnyOrder("li.strolch.privilege.handler.SystemUserAction")); + + IPrivilege testSystemUserAction2 = restrictedRole + .getPrivilege("li.strolch.privilege.handler.SystemUserAction"); + assertEquals("li.strolch.privilege.handler.SystemUserAction", testSystemUserAction2.getName()); + assertEquals("DefaultPrivilege", testSystemUserAction2.getPolicy()); + assertFalse(testSystemUserAction2.isAllAllowed()); + assertEquals(1, testSystemUserAction2.getAllowList().size()); + assertEquals(1, testSystemUserAction2.getDenyList().size()); + assertThat(testSystemUserAction2.getAllowList(), containsInAnyOrder("hello")); + assertThat(testSystemUserAction2.getDenyList(), containsInAnyOrder("goodbye")); + } + + /** + * @param username + * @param users + * @return + */ + private User findUser(String username, List users) { + for (User user : users) { + if (user.getUsername().equals(username)) + return user; + } + + throw new RuntimeException("No user exists with username " + username); + } + + /** + * @param name + * @param roles + * @return + */ + private Role findRole(String name, List roles) { + for (Role role : roles) { + if (role.getName().equals(name)) + return role; + } + + throw new RuntimeException("No role exists with name " + name); + } + + @Test + public void canWriteUsers() { + + Map propertyMap; + Set userRoles; + + List users = new ArrayList<>(); + propertyMap = new HashMap<>(); + propertyMap.put("prop1", "value1"); + userRoles = new HashSet<>(); + userRoles.add("role1"); + User user1 = new User("1", "user1", "blabla", "Bob", "White", UserState.DISABLED, userRoles, Locale.ENGLISH, + propertyMap); + users.add(user1); + + propertyMap = new HashMap<>(); + propertyMap.put("prop2", "value2"); + userRoles = new HashSet<>(); + userRoles.add("role2"); + User user2 = new User("2", "user2", "haha", "Leonard", "Sheldon", UserState.ENABLED, userRoles, Locale.ENGLISH, + propertyMap); + users.add(user2); + + File modelFile = new File("./target/test/PrivilegeUsersTest.xml"); + PrivilegeUsersDomWriter configSaxWriter = new PrivilegeUsersDomWriter(users, modelFile); + configSaxWriter.write(); + + PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader(); + XmlHelper.parseDocument(modelFile, xmlHandler); + + List parsedUsers = xmlHandler.getUsers(); + assertNotNull(parsedUsers); + assertEquals(2, parsedUsers.size()); + + User parsedUser1 = parsedUsers.stream().filter(u -> u.getUsername().equals("user1")).findAny().get(); + User parsedUser2 = parsedUsers.stream().filter(u -> u.getUsername().equals("user2")).findAny().get(); + + assertEquals(user1.getFirstname(), parsedUser1.getFirstname()); + assertEquals(user1.getLastname(), parsedUser1.getLastname()); + assertEquals(user1.getLocale(), parsedUser1.getLocale()); + assertEquals(user1.getPassword(), parsedUser1.getPassword()); + assertEquals(user1.getProperties(), parsedUser1.getProperties()); + assertEquals(user1.getUserId(), parsedUser1.getUserId()); + assertEquals(user1.getUserState(), parsedUser1.getUserState()); + assertEquals(user1.getRoles(), parsedUser1.getRoles()); + + assertEquals(user2.getFirstname(), parsedUser2.getFirstname()); + assertEquals(user2.getLastname(), parsedUser2.getLastname()); + assertEquals(user2.getLocale(), parsedUser2.getLocale()); + assertEquals(user2.getPassword(), parsedUser2.getPassword()); + assertEquals(user2.getProperties(), parsedUser2.getProperties()); + assertEquals(user2.getUserId(), parsedUser2.getUserId()); + assertEquals(user2.getUserState(), parsedUser2.getUserState()); + assertEquals(user2.getRoles(), parsedUser2.getRoles()); + } + + @Test + public void canWriteRoles() { + + Map privilegeMap; + List roles = new ArrayList<>(); + Set list = Collections.emptySet(); + privilegeMap = new HashMap<>(); + privilegeMap.put("priv1", new PrivilegeImpl("priv1", "DefaultPrivilege", true, list, list)); + Role role1 = new Role("role1", privilegeMap); + roles.add(role1); + + privilegeMap = new HashMap<>(); + Set denyList = new HashSet<>(); + denyList.add("myself"); + Set allowList = new HashSet<>(); + allowList.add("other"); + privilegeMap.put("priv2", new PrivilegeImpl("priv2", "DefaultPrivilege", false, denyList, allowList)); + Role role2 = new Role("role2", privilegeMap); + roles.add(role2); + + File modelFile = new File("./target/test/PrivilegeRolesTest.xml"); + PrivilegeRolesDomWriter configSaxWriter = new PrivilegeRolesDomWriter(roles, modelFile); + configSaxWriter.write(); + + PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader(); + XmlHelper.parseDocument(modelFile, xmlHandler); + + List parsedRoles = xmlHandler.getRoles(); + assertNotNull(parsedRoles); + assertEquals(2, parsedRoles.size()); + + assertEquals(2, parsedRoles.size()); + Role parsedRole1 = parsedRoles.stream().filter(r -> r.getName().equals("role1")).findAny().get(); + Role parsedRole2 = parsedRoles.stream().filter(r -> r.getName().equals("role2")).findAny().get(); + + Set privilegeNames = role1.getPrivilegeNames(); + assertEquals(privilegeNames, parsedRole1.getPrivilegeNames()); + for (String privilegeName : privilegeNames) { + IPrivilege privilege = role1.getPrivilege(privilegeName); + IPrivilege privilege2 = parsedRole1.getPrivilege(privilegeName); + assertNotNull(privilege); + assertNotNull(privilege2); + + assertEquals(privilege.isAllAllowed(), privilege2.isAllAllowed()); + assertEquals(privilege.getAllowList(), privilege2.getAllowList()); + assertEquals(privilege.getDenyList(), privilege2.getDenyList()); + assertEquals(privilege.getName(), privilege2.getName()); + assertEquals(privilege.getPolicy(), privilege2.getPolicy()); + } + + assertEquals(role2.getPrivilegeNames(), parsedRole2.getPrivilegeNames()); + privilegeNames = role2.getPrivilegeNames(); + for (String privilegeName : privilegeNames) { + IPrivilege privilege = role2.getPrivilege(privilegeName); + IPrivilege privilege2 = parsedRole2.getPrivilege(privilegeName); + assertNotNull(privilege); + assertNotNull(privilege2); + + assertEquals(privilege.isAllAllowed(), privilege2.isAllAllowed()); + assertEquals(privilege.getAllowList(), privilege2.getAllowList()); + assertEquals(privilege.getDenyList(), privilege2.getDenyList()); + assertEquals(privilege.getName(), privilege2.getName()); + assertEquals(privilege.getPolicy(), privilege2.getPolicy()); + } + } +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestRestrictable.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestRestrictable.java new file mode 100644 index 000000000..66bc6c892 --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestRestrictable.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test.model; + +import li.strolch.privilege.model.Restrictable; + +/** + * @author Robert von Burg + * + */ +public class TestRestrictable implements Restrictable { + + /** + * @see li.strolch.privilege.model.Restrictable#getPrivilegeName() + */ + @Override + public String getPrivilegeName() { + return TestRestrictable.class.getName(); + } + + /** + * @see li.strolch.privilege.model.Restrictable#getPrivilegeValue() + */ + @Override + public Object getPrivilegeValue() { + return TestRestrictable.class.getName(); + } + +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemRestrictable.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemRestrictable.java new file mode 100644 index 000000000..1f8e9be39 --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemRestrictable.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test.model; + +import li.strolch.privilege.model.Restrictable; + +/** + * @author Robert von Burg + * + */ +public class TestSystemRestrictable implements Restrictable { + + /** + * @see li.strolch.privilege.model.Restrictable#getPrivilegeName() + */ + @Override + public String getPrivilegeName() { + return TestSystemRestrictable.class.getName(); + } + + /** + * @see li.strolch.privilege.model.Restrictable#getPrivilegeValue() + */ + @Override + public Object getPrivilegeValue() { + return TestSystemRestrictable.class.getName(); + } + +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemUserAction.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemUserAction.java new file mode 100644 index 000000000..99c3f7744 --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemUserAction.java @@ -0,0 +1,32 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test.model; + +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; + +/** + * @author Robert von Burg + * + */ +public class TestSystemUserAction extends SystemUserAction { + + @Override + public void execute(PrivilegeContext context) { + TestSystemRestrictable restrictable = new TestSystemRestrictable(); + context.validateAction(restrictable); + } +} diff --git a/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemUserActionDeny.java b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemUserActionDeny.java new file mode 100644 index 000000000..1eb7d1501 --- /dev/null +++ b/li.strolch.privilege/src/test/java/li/strolch/privilege/test/model/TestSystemUserActionDeny.java @@ -0,0 +1,32 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.privilege.test.model; + +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; + +/** + * @author Robert von Burg + * + */ +public class TestSystemUserActionDeny extends SystemUserAction { + + @Override + public void execute(PrivilegeContext privilegeContext) { + TestRestrictable restrictable = new TestRestrictable(); + privilegeContext.validateAction(restrictable); + } +} diff --git a/li.strolch.privilege/src/test/resources/log4j.xml b/li.strolch.privilege/src/test/resources/log4j.xml new file mode 100644 index 000000000..7a0499275 --- /dev/null +++ b/li.strolch.privilege/src/test/resources/log4j.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/li.strolch.rest/pom.xml b/li.strolch.rest/pom.xml index 9f8c26293..db0d34aa3 100644 --- a/li.strolch.rest/pom.xml +++ b/li.strolch.rest/pom.xml @@ -1,38 +1,20 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.rest - li.strolch.rest Restful Web Service API for Strolch - - https://github.com/eitchnet/li.strolch.rest - 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.rest/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - - - 2.11 - - @@ -60,18 +42,16 @@ li.strolch.service - - - javax.servlet - javax.servlet-api - - javax.mail mail - + + + javax.servlet + javax.servlet-api + org.glassfish.jersey.containers jersey-container-servlet diff --git a/li.strolch.rest/src/main/java/li/strolch/model/query/parser/QueryParser.java b/li.strolch.rest/src/main/java/li/strolch/model/query/parser/QueryParser.java index 1c0046cb7..49de40c77 100644 --- a/li.strolch.rest/src/main/java/li/strolch/model/query/parser/QueryParser.java +++ b/li.strolch.rest/src/main/java/li/strolch/model/query/parser/QueryParser.java @@ -8,7 +8,6 @@ import org.petitparser.context.Result; import org.petitparser.parser.Parser; import org.petitparser.tools.CompositeParser; -import ch.eitchnet.utils.StringMatchMode; import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.activity.Activity; @@ -23,6 +22,7 @@ import li.strolch.model.query.StrolchTypeNavigation; import li.strolch.model.visitor.NoStrategyActivityVisitor; import li.strolch.model.visitor.NoStrategyOrderVisitor; import li.strolch.model.visitor.NoStrategyResourceVisitor; +import li.strolch.utils.StringMatchMode; public class QueryParser extends CompositeParser { diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java b/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java index 54650d10b..ebf065e3b 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java @@ -38,18 +38,18 @@ import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.base.AccessDeniedException; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.privilege.model.SimpleRestrictable; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.exception.StrolchException; +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeContext; +import li.strolch.privilege.model.SimpleRestrictable; import li.strolch.rest.model.UserSession; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/RestfulStrolchComponent.java b/li.strolch.rest/src/main/java/li/strolch/rest/RestfulStrolchComponent.java index 09572d252..ddddfc7d4 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/RestfulStrolchComponent.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/RestfulStrolchComponent.java @@ -19,7 +19,6 @@ import java.text.MessageFormat; import org.glassfish.jersey.server.ServerProperties; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchComponent; @@ -27,6 +26,7 @@ import li.strolch.rest.filters.AccessControlResponseFilter; import li.strolch.rest.filters.HttpCacheResponseFilter; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.service.api.ServiceHandler; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java index 9f7d5beb3..5a3ef6c77 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java @@ -27,10 +27,10 @@ import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Restrictable; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.exception.StrolchAccessDeniedException; +import li.strolch.privilege.model.Restrictable; import li.strolch.rest.model.Result; +import li.strolch.utils.helper.StringHelper; @Provider public class StrolchRestfulExceptionMapper implements ExceptionMapper { diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java index b3d6604a8..b8e1d0085 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java @@ -18,8 +18,8 @@ package li.strolch.rest; import java.util.List; import java.util.Locale; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.model.UserSession; -import ch.eitchnet.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuditsService.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuditsService.java index b8c4ab59d..0bee71f9f 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuditsService.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuditsService.java @@ -32,13 +32,13 @@ import javax.ws.rs.core.Response; import li.strolch.agent.api.StrolchRealm; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.model.AuditQuery; import li.strolch.rest.model.AuditQueryResult; import li.strolch.rest.model.StringListResult; import li.strolch.rest.model.visitor.ToAuditQueryVisitor; -import ch.eitchnet.privilege.model.Certificate; @Path("strolch/audits") public class AuditsService { diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuthenticationService.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuthenticationService.java index cd7d597f7..af721eb91 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuthenticationService.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/AuthenticationService.java @@ -42,14 +42,13 @@ import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.JsonObject; -import ch.eitchnet.privilege.base.AccessDeniedException; -import ch.eitchnet.privilege.base.InvalidCredentialsException; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.IPrivilege; -import ch.eitchnet.privilege.model.PrivilegeContext; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.exception.StrolchException; +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.InvalidCredentialsException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.IPrivilege; +import li.strolch.privilege.model.PrivilegeContext; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.StrolchSessionHandler; @@ -57,6 +56,7 @@ import li.strolch.rest.model.Login; import li.strolch.rest.model.LoginResult; import li.strolch.rest.model.LogoutResult; import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/EnumQuery.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/EnumQuery.java index f07a9f7a4..8f6b23f39 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/EnumQuery.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/EnumQuery.java @@ -28,6 +28,7 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.helper.RestfulHelper; @@ -37,8 +38,6 @@ import li.strolch.runtime.query.enums.StrolchEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; - /** * @author Robert von Burg */ diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java index f68da826a..a29cb9c30 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java @@ -38,7 +38,6 @@ import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; @@ -53,6 +52,7 @@ import li.strolch.model.xml.SimpleStrolchElementListener; import li.strolch.model.xml.XmlModelSaxReader; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.model.AgentOverview; diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java index c9f00d80c..6a30c3fd1 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java @@ -21,9 +21,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.collections.Paging; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.ActivityMap; import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; @@ -42,9 +39,12 @@ import li.strolch.model.query.StrolchTypeNavigation; import li.strolch.model.query.parser.QueryParser; import li.strolch.model.visitor.StrolchElementVisitor; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.runtime.StrolchConstants; +import li.strolch.utils.collections.Paging; +import li.strolch.utils.helper.StringHelper; @Path("strolch/model") public class ModelQuery { diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegePoliciesService.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegePoliciesService.java index 8a2253626..4adf20f5f 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegePoliciesService.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegePoliciesService.java @@ -28,11 +28,11 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import li.strolch.agent.api.ComponentContainer; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.xml.XmlKeyValue; +import li.strolch.utils.xml.XmlKeyValue; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeRolesService.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeRolesService.java index 410398db6..820658b75 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeRolesService.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeRolesService.java @@ -33,6 +33,12 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import li.strolch.agent.api.ComponentContainer; +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.RoleRep; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.model.Result; @@ -47,12 +53,6 @@ import li.strolch.service.privilege.roles.PrivilegeRoleArgument; import li.strolch.service.privilege.roles.PrivilegeRoleNameArgument; import li.strolch.service.privilege.roles.PrivilegeRoleResult; import li.strolch.service.privilege.roles.PrivilegeUpdateRoleService; -import ch.eitchnet.privilege.base.AccessDeniedException; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.PrivilegeRep; -import ch.eitchnet.privilege.model.RoleRep; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeUsersService.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeUsersService.java index 13de4c635..fb6640573 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeUsersService.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/PrivilegeUsersService.java @@ -34,13 +34,13 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; -import ch.eitchnet.privilege.base.AccessDeniedException; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.UserRep; -import ch.eitchnet.privilege.model.UserState; import li.strolch.agent.api.ComponentContainer; +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.UserRep; +import li.strolch.privilege.model.UserState; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.StrolchSessionHandler; diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/UserSessionsService.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/UserSessionsService.java index d11cee79b..2b9451ff2 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/UserSessionsService.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/UserSessionsService.java @@ -31,6 +31,7 @@ import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.StrolchSessionHandler; @@ -40,8 +41,6 @@ import li.strolch.rest.model.UserSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; - @Path("strolch/sessions") public class UserSessionsService { diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/VersionQuery.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/VersionQuery.java index 3d0be058c..4f62f2521 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/VersionQuery.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/VersionQuery.java @@ -25,9 +25,9 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import li.strolch.agent.api.VersionQueryResult; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; -import ch.eitchnet.privilege.model.Certificate; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationRequestFilter.java b/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationRequestFilter.java index 75095c390..546df349f 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationRequestFilter.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationRequestFilter.java @@ -31,11 +31,11 @@ import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; import li.strolch.rest.StrolchSessionHandler; +import li.strolch.utils.helper.StringHelper; /** * @author Reto Breitenmoser diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationResponseFilter.java b/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationResponseFilter.java index a02481b2b..00a1f3c39 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationResponseFilter.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenicationResponseFilter.java @@ -25,7 +25,7 @@ import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.ext.Provider; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; /** * @author Reto Breitenmoser diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java b/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java index 90caef104..73e24bf48 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java @@ -20,10 +20,10 @@ import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.HttpHeaders; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.dbc.DBC; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.privilege.model.Certificate; import li.strolch.rest.StrolchRestfulConstants; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/AuditQueryResult.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/AuditQueryResult.java index 6c382bf9e..03b8cd0ec 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/AuditQueryResult.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/AuditQueryResult.java @@ -24,7 +24,7 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import li.strolch.model.audit.Audit; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; @XmlRootElement(name = "AuditQueryResult") @XmlAccessorType(XmlAccessType.NONE) diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/LoginResult.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/LoginResult.java index e5e5831ba..a299d072a 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/LoginResult.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/LoginResult.java @@ -26,7 +26,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import ch.eitchnet.utils.xml.XmlKeyValue; +import li.strolch.utils.xml.XmlKeyValue; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/OrderOverview.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/OrderOverview.java index 46b6581cf..824e96efe 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/OrderOverview.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/OrderOverview.java @@ -24,7 +24,7 @@ import javax.xml.bind.annotation.XmlRootElement; import li.strolch.model.Order; import li.strolch.model.State; -import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/Result.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/Result.java index 3f0a20ac8..0c3866a40 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/Result.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/Result.java @@ -22,8 +22,8 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.service.api.ServiceResult; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/StringListResult.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/StringListResult.java index 9b77a78ec..a2b5090c8 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/StringListResult.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/StringListResult.java @@ -23,7 +23,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; @XmlRootElement(name = "StringListResult") @XmlAccessorType(XmlAccessType.NONE) diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/UserSession.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/UserSession.java index b86d19a1d..803e20a35 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/UserSession.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/UserSession.java @@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import ch.eitchnet.privilege.model.Certificate; +import li.strolch.privilege.model.Certificate; @XmlRootElement(name = "UserSession") @XmlAccessorType(XmlAccessType.NONE) diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/model/visitor/ToAuditQueryVisitor.java b/li.strolch.rest/src/main/java/li/strolch/rest/model/visitor/ToAuditQueryVisitor.java index 7c2dc9552..95a45215c 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/model/visitor/ToAuditQueryVisitor.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/model/visitor/ToAuditQueryVisitor.java @@ -23,8 +23,8 @@ import li.strolch.rest.model.ActionSelection; import li.strolch.rest.model.AuditQuery; import li.strolch.rest.model.DateRange; import li.strolch.rest.model.IdentitySelection; -import ch.eitchnet.utils.StringMatchMode; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.StringMatchMode; +import li.strolch.utils.helper.StringHelper; public class ToAuditQueryVisitor { @@ -41,7 +41,7 @@ public class ToAuditQueryVisitor { if (dateRange == null || dateRange.getFromDate() == null || dateRange.getToDate() == null) { throw new IllegalArgumentException("DateRange on AuditQuery is not valid or is missing!"); } - ch.eitchnet.utils.collections.DateRange dr = new ch.eitchnet.utils.collections.DateRange().from( + li.strolch.utils.collections.DateRange dr = new li.strolch.utils.collections.DateRange().from( dateRange.getFromDate(), dateRange.isFromInclusive()).to(dateRange.getToDate(), dateRange.isToInclusive()); diff --git a/li.strolch.rest/src/test/resources/log4j.xml b/li.strolch.rest/src/test/resources/log4j.xml index 0a2a73d06..7a0499275 100644 --- a/li.strolch.rest/src/test/resources/log4j.xml +++ b/li.strolch.rest/src/test/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml b/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml +++ b/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeModel.xml b/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeModel.xml index d0c963b04..0110c6a4d 100644 --- a/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeModel.xml +++ b/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeModel.xml @@ -57,7 +57,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml b/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml index a2dbfc80e..a113935c1 100644 --- a/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml +++ b/li.strolch.rest/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.service/pom.xml b/li.strolch.service/pom.xml index 21436d05f..8d4caa408 100644 --- a/li.strolch.service/pom.xml +++ b/li.strolch.service/pom.xml @@ -1,115 +1,100 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml - + + li.strolch + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml + - li.strolch.service + li.strolch.service + li.strolch.service + Service API for Strolch + 2011 - li.strolch.service - Service API for Strolch + + + + li.strolch + li.strolch.model + + + li.strolch + li.strolch.agent + - https://github.com/eitchnet/li.strolch.service + + li.strolch + li.strolch.xmlpers + + + li.strolch + li.strolch.privilege + - 2011 + + + org.mockito + mockito-core + 2.0.8-beta + - - Github Issues - https://github.com/eitchnet/li.strolch.service/issues - + + + li.strolch + li.strolch.testbase + + + li.strolch + li.strolch.persistence.postgresql + test + - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - + - - - - li.strolch - li.strolch.model - - - li.strolch - li.strolch.agent - + + + + src/main/resources + true + + **/componentVersion.properties + + + - - ch.eitchnet - ch.eitchnet.xmlpers - - - ch.eitchnet - ch.eitchnet.privilege - + + + org.codehaus.mojo + buildnumber-maven-plugin + + + org.apache.maven.plugins + maven-eclipse-plugin + - - - org.mockito - mockito-core - 2.0.8-beta - + + org.apache.maven.plugins + maven-compiler-plugin + - - - li.strolch - li.strolch.testbase - - - li.strolch - li.strolch.persistence.postgresql - test - + + org.apache.maven.plugins + maven-source-plugin + - + + org.apache.maven.plugins + maven-jar-plugin + - - - - src/main/resources - true - - **/componentVersion.properties - - - - - - - org.codehaus.mojo - buildnumber-maven-plugin - - - org.apache.maven.plugins - maven-eclipse-plugin - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.apache.maven.plugins - maven-source-plugin - - - - org.apache.maven.plugins - maven-jar-plugin - - - - org.apache.maven.plugins - maven-site-plugin - - - + + org.apache.maven.plugins + maven-site-plugin + + + diff --git a/li.strolch.service/src/main/java/li/strolch/command/AddOrderCollectionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/AddOrderCollectionCommand.java index b8cda78ed..9c70b8a9d 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/AddOrderCollectionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/AddOrderCollectionCommand.java @@ -24,7 +24,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/AddOrderCommand.java b/li.strolch.service/src/main/java/li/strolch/command/AddOrderCommand.java index 96a12dcde..7b8e30de0 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/AddOrderCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/AddOrderCommand.java @@ -23,7 +23,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/AddResourceCollectionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/AddResourceCollectionCommand.java index e3c15b5fa..72a5d18fb 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/AddResourceCollectionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/AddResourceCollectionCommand.java @@ -24,7 +24,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/AddResourceCommand.java b/li.strolch.service/src/main/java/li/strolch/command/AddResourceCommand.java index efed9e001..7b9615a48 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/AddResourceCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/AddResourceCommand.java @@ -23,7 +23,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCollectionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCollectionCommand.java index fd0b73b9e..1fca5b8e9 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCollectionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCollectionCommand.java @@ -24,7 +24,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCommand.java b/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCommand.java index 908aa7958..ab1140540 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/RemoveOrderCommand.java @@ -23,7 +23,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCollectionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCollectionCommand.java index 438746af5..873cb5954 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCollectionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCollectionCommand.java @@ -24,7 +24,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCommand.java b/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCommand.java index 1a0e5b2b4..c392eceff 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/RemoveResourceCommand.java @@ -23,7 +23,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCollectionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCollectionCommand.java index 693af78dd..2959f7089 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCollectionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCollectionCommand.java @@ -24,7 +24,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCommand.java b/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCommand.java index 48c81ffd2..450570037 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/UpdateOrderCommand.java @@ -23,7 +23,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCollectionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCollectionCommand.java index 031ca510c..5dc693af3 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCollectionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCollectionCommand.java @@ -24,7 +24,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCommand.java b/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCommand.java index 6c3194ee9..e1638b582 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/UpdateResourceCommand.java @@ -23,7 +23,7 @@ import li.strolch.exception.StrolchException; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java b/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java index 52969fd42..f32915d01 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java @@ -15,7 +15,7 @@ */ package li.strolch.command; -import static ch.eitchnet.utils.helper.StringHelper.UNDERLINE; +import static li.strolch.utils.helper.StringHelper.UNDERLINE; import java.io.File; import java.io.FileOutputStream; @@ -53,7 +53,7 @@ import li.strolch.model.xml.ResourceToSaxWriterVisitor; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java b/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java index ad2db34c3..ecdac62c0 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java @@ -24,7 +24,7 @@ import li.strolch.model.ModelStatistics; import li.strolch.model.xml.XmlModelSaxFileReader; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/parameter/AddParameterCommand.java b/li.strolch.service/src/main/java/li/strolch/command/parameter/AddParameterCommand.java index 491220c54..1273e8720 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/parameter/AddParameterCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/parameter/AddParameterCommand.java @@ -25,7 +25,7 @@ import li.strolch.model.parameter.Parameter; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/parameter/RemoveParameterCommand.java b/li.strolch.service/src/main/java/li/strolch/command/parameter/RemoveParameterCommand.java index 5ce3c0347..2d44e3f5d 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/parameter/RemoveParameterCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/parameter/RemoveParameterCommand.java @@ -25,7 +25,7 @@ import li.strolch.model.parameter.Parameter; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/parameter/SetParameterCommand.java b/li.strolch.service/src/main/java/li/strolch/command/parameter/SetParameterCommand.java index a40b415f3..bcffd8189 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/parameter/SetParameterCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/parameter/SetParameterCommand.java @@ -22,7 +22,7 @@ import li.strolch.model.parameter.Parameter; import li.strolch.model.visitor.SetParameterValueVisitor; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/command/plan/AssignActionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/plan/AssignActionCommand.java index a9047d915..fadddf8ba 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/plan/AssignActionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/plan/AssignActionCommand.java @@ -19,7 +19,7 @@ import li.strolch.agent.api.ComponentContainer; import li.strolch.model.Resource; import li.strolch.model.activity.Action; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * Command to assign an {@link Action} to a new {@link Resource}. diff --git a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java index acc4f9dae..cfe86e67f 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java @@ -22,7 +22,7 @@ import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.IValueChange; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * Command to plan an {@link Action} to a {@link Resource}. This {@link Command} diff --git a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java index d90f65a44..dab68784f 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java @@ -27,7 +27,7 @@ import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.IValueChange; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.Command; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * Command to plan an {@link Activity} to a {@link Resource}. This diff --git a/li.strolch.service/src/main/java/li/strolch/command/plan/ShiftActionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/plan/ShiftActionCommand.java index 84b1db80f..ac4fae40d 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/plan/ShiftActionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/plan/ShiftActionCommand.java @@ -22,7 +22,7 @@ import li.strolch.model.State; import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.IValueChange; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC; /** * @author Martin Smock diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/CodeMigration.java b/li.strolch.service/src/main/java/li/strolch/migrations/CodeMigration.java index 1cd48a1b7..5cab7782e 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/CodeMigration.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/CodeMigration.java @@ -21,8 +21,8 @@ import li.strolch.agent.api.ComponentContainer; import li.strolch.command.parameter.SetParameterCommand; import li.strolch.model.Resource; import li.strolch.model.parameter.StringParameter; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; +import li.strolch.privilege.model.Certificate; +import li.strolch.utils.Version; public class CodeMigration extends Migration { diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/CurrentMigrationVersionQuery.java b/li.strolch.service/src/main/java/li/strolch/migrations/CurrentMigrationVersionQuery.java index ae056e4d1..777dadce5 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/CurrentMigrationVersionQuery.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/CurrentMigrationVersionQuery.java @@ -29,9 +29,9 @@ import li.strolch.agent.api.StrolchRealm; import li.strolch.model.Resource; import li.strolch.model.parameter.StringParameter; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.StrolchConfigurationException; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; +import li.strolch.utils.Version; public class CurrentMigrationVersionQuery { diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/DataMigration.java b/li.strolch.service/src/main/java/li/strolch/migrations/DataMigration.java index 3bdea55d2..69470c330 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/DataMigration.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/DataMigration.java @@ -27,8 +27,8 @@ import li.strolch.model.ModelStatistics; import li.strolch.model.Resource; import li.strolch.model.parameter.StringParameter; import li.strolch.persistence.api.StrolchTransaction; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; +import li.strolch.privilege.model.Certificate; +import li.strolch.utils.Version; public class DataMigration extends Migration { diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/Migration.java b/li.strolch.service/src/main/java/li/strolch/migrations/Migration.java index d1ecb7878..ec3342383 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/Migration.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/Migration.java @@ -24,13 +24,12 @@ import li.strolch.model.ParameterBag; import li.strolch.model.Resource; import li.strolch.model.parameter.StringParameter; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; +import li.strolch.utils.Version; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; - public abstract class Migration { public static final String MIGRATIONS_TYPE = "Migrations"; diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/MigrationVersion.java b/li.strolch.service/src/main/java/li/strolch/migrations/MigrationVersion.java index 6ead4d919..ecd4c9a73 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/MigrationVersion.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/MigrationVersion.java @@ -3,7 +3,7 @@ */ package li.strolch.migrations; -import ch.eitchnet.utils.Version; +import li.strolch.utils.Version; /** * Migration versions for data and code migrations diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java b/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java index 184691b84..661ce138e 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java @@ -27,15 +27,14 @@ import java.util.SortedSet; import java.util.TreeSet; import li.strolch.agent.api.ComponentContainer; +import li.strolch.privilege.model.Certificate; +import li.strolch.utils.Version; +import li.strolch.utils.collections.MapOfLists; +import li.strolch.utils.dbc.DBC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; -import ch.eitchnet.utils.collections.MapOfLists; -import ch.eitchnet.utils.dbc.DBC; - public class Migrations { private static final Logger logger = LoggerFactory.getLogger(Migrations.class); diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java b/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java index 6ac3a33e7..e5bbeddd5 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java @@ -24,12 +24,12 @@ import java.util.concurrent.TimeUnit; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.RealmHandler; import li.strolch.agent.api.StrolchComponent; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; -import ch.eitchnet.utils.collections.MapOfLists; +import li.strolch.utils.Version; +import li.strolch.utils.collections.MapOfLists; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/QueryCurrentVersionsAction.java b/li.strolch.service/src/main/java/li/strolch/migrations/QueryCurrentVersionsAction.java index af12fdc03..df6181d67 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/QueryCurrentVersionsAction.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/QueryCurrentVersionsAction.java @@ -15,8 +15,8 @@ */ package li.strolch.migrations; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java b/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java index 4ee126ec6..22fe00ca8 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java @@ -17,8 +17,8 @@ package li.strolch.migrations; import java.util.Map; -import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.PrivilegeContext; +import li.strolch.privilege.handler.SystemUserAction; +import li.strolch.privilege.model.PrivilegeContext; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/ClearModelService.java b/li.strolch.service/src/main/java/li/strolch/service/ClearModelService.java index b1a5d3812..b5ac46b9a 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/ClearModelService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/ClearModelService.java @@ -22,7 +22,7 @@ import li.strolch.model.ModelStatistics; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceResult; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/XmlExportModelService.java b/li.strolch.service/src/main/java/li/strolch/service/XmlExportModelService.java index ae7feb45b..adc36c120 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/XmlExportModelService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/XmlExportModelService.java @@ -18,12 +18,12 @@ package li.strolch.service; import java.io.File; import java.text.MessageFormat; -import ch.eitchnet.utils.dbc.DBC; import li.strolch.command.XmlExportModelCommand; import li.strolch.model.ModelStatistics; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceResult; +import li.strolch.utils.dbc.DBC; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java b/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java index f577b0a33..afb245366 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java @@ -24,7 +24,7 @@ import li.strolch.model.ModelStatistics; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceResultState; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionHandler.java b/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionHandler.java index 81b095635..29fce8d13 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionHandler.java +++ b/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionHandler.java @@ -21,16 +21,16 @@ import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.helper.ExceptionHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.exception.StrolchException; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.service.api.Service; import li.strolch.service.api.ServiceArgument; import li.strolch.service.api.ServiceHandler; import li.strolch.service.api.ServiceResult; +import li.strolch.utils.helper.ExceptionHelper; /** * The {@link ServiceExecutionHandler} is used to perform long running services so that no singletons etc. are required. diff --git a/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionStatus.java b/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionStatus.java index 91f4d72a7..6824e8ca6 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionStatus.java +++ b/li.strolch.service/src/main/java/li/strolch/service/executor/ServiceExecutionStatus.java @@ -21,7 +21,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import li.strolch.service.api.ServiceResult; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleArgument.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleArgument.java index 79a7cedac..4e9014eeb 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleArgument.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleArgument.java @@ -15,7 +15,7 @@ */ package li.strolch.service.privilege.roles; -import ch.eitchnet.privilege.model.PrivilegeRep; +import li.strolch.privilege.model.PrivilegeRep; import li.strolch.service.api.ServiceArgument; public class PrivilegeAddOrReplacePrivilegeOnRoleArgument extends ServiceArgument { diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleService.java index 3c7d0eb05..7d39db95e 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddOrReplacePrivilegeOnRoleService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.roles; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.RoleRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.RoleRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddRoleService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddRoleService.java index 85adf71a5..a2685bddb 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddRoleService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeAddRoleService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.roles; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.RoleRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.RoleRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemovePrivilegeFromRoleService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemovePrivilegeFromRoleService.java index 5c8421892..77cfc29f2 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemovePrivilegeFromRoleService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemovePrivilegeFromRoleService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.roles; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.RoleRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.RoleRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemoveRoleService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemoveRoleService.java index 95c1bf2cd..aee46596b 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemoveRoleService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRemoveRoleService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.roles; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.RoleRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.RoleRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleArgument.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleArgument.java index df6a1773f..a7d258442 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleArgument.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleArgument.java @@ -15,8 +15,8 @@ */ package li.strolch.service.privilege.roles; +import li.strolch.privilege.model.RoleRep; import li.strolch.service.api.ServiceArgument; -import ch.eitchnet.privilege.model.RoleRep; public class PrivilegeRoleArgument extends ServiceArgument { private static final long serialVersionUID = 1L; diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleResult.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleResult.java index 463505811..9902b8950 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleResult.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeRoleResult.java @@ -15,9 +15,9 @@ */ package li.strolch.service.privilege.roles; +import li.strolch.privilege.model.RoleRep; import li.strolch.service.api.ServiceResult; import li.strolch.service.api.ServiceResultState; -import ch.eitchnet.privilege.model.RoleRep; public class PrivilegeRoleResult extends ServiceResult { private static final long serialVersionUID = 1L; diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeUpdateRoleService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeUpdateRoleService.java index de11892c7..50ffc6fed 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeUpdateRoleService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/roles/PrivilegeUpdateRoleService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.roles; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.RoleRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.RoleRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddRoleToUserService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddRoleToUserService.java index 31be74506..4d99a769c 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddRoleToUserService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddRoleToUserService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddUserService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddUserService.java index 8f940a678..ecf4f3aaa 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddUserService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeAddUserService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveRoleFromUserService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveRoleFromUserService.java index 93e860d47..a0b9a33a7 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveRoleFromUserService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveRoleFromUserService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveUserService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveUserService.java index 80a3ed6c6..6c8e6a3a1 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveUserService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeRemoveUserService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserLocaleService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserLocaleService.java index 6e56be423..eab459d5b 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserLocaleService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserLocaleService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserPasswordService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserPasswordService.java index 8c2dd96d9..924ac4775 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserPasswordService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserPasswordService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceResult; -import ch.eitchnet.privilege.handler.PrivilegeHandler; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateArgument.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateArgument.java index 6a5333099..98c56e196 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateArgument.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateArgument.java @@ -15,8 +15,8 @@ */ package li.strolch.service.privilege.users; +import li.strolch.privilege.model.UserState; import li.strolch.service.api.ServiceArgument; -import ch.eitchnet.privilege.model.UserState; public class PrivilegeSetUserStateArgument extends ServiceArgument { private static final long serialVersionUID = 1L; diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateService.java index a6bd59d13..99fd7d8ce 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeSetUserStateService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUpdateUserService.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUpdateUserService.java index f197713ff..1b647bb55 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUpdateUserService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUpdateUserService.java @@ -18,10 +18,10 @@ package li.strolch.service.privilege.users; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.handler.PrivilegeHandler; +import li.strolch.privilege.model.UserRep; import li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants; import li.strolch.service.api.AbstractService; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.UserRep; /** * @author Robert von Burg diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserArgument.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserArgument.java index db0402e09..f7b8bc6ed 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserArgument.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserArgument.java @@ -15,8 +15,8 @@ */ package li.strolch.service.privilege.users; +import li.strolch.privilege.model.UserRep; import li.strolch.service.api.ServiceArgument; -import ch.eitchnet.privilege.model.UserRep; public class PrivilegeUserArgument extends ServiceArgument { private static final long serialVersionUID = 1L; diff --git a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserResult.java b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserResult.java index 51f46266c..94ee5553a 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserResult.java +++ b/li.strolch.service/src/main/java/li/strolch/service/privilege/users/PrivilegeUserResult.java @@ -15,9 +15,9 @@ */ package li.strolch.service.privilege.users; +import li.strolch.privilege.model.UserRep; import li.strolch.service.api.ServiceResult; import li.strolch.service.api.ServiceResultState; -import ch.eitchnet.privilege.model.UserRep; public class PrivilegeUserResult extends ServiceResult { private static final long serialVersionUID = 1L; diff --git a/li.strolch.service/src/test/java/li/strolch/command/AbstractRealmCommandTest.java b/li.strolch.service/src/test/java/li/strolch/command/AbstractRealmCommandTest.java index 967f14d28..8d4481dfc 100644 --- a/li.strolch.service/src/test/java/li/strolch/command/AbstractRealmCommandTest.java +++ b/li.strolch.service/src/test/java/li/strolch/command/AbstractRealmCommandTest.java @@ -28,6 +28,7 @@ import java.io.File; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchRealm; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.service.api.Command; import li.strolch.service.api.ServiceHandler; import li.strolch.testbase.runtime.RuntimeMock; @@ -38,8 +39,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import ch.eitchnet.privilege.model.Certificate; - /** * @author Robert von Burg */ diff --git a/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java b/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java index 3e4a5b4b3..5503a8192 100644 --- a/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java +++ b/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java @@ -29,17 +29,16 @@ import li.strolch.command.RemoveOrderCommand; import li.strolch.model.ModelGenerator; import li.strolch.model.Order; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.Version; +import li.strolch.utils.collections.MapOfLists; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; -import ch.eitchnet.utils.collections.MapOfLists; - public class MigrationsTest { public static final String RUNTIME_PATH = "target/migrationstest/"; //$NON-NLS-1$ diff --git a/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java b/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java index 8f59bec5e..0849dd1ab 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java @@ -25,11 +25,10 @@ import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceArgument; import li.strolch.service.api.ServiceResult; import li.strolch.service.test.AbstractRealmServiceTest; +import li.strolch.utils.dbc.DBC; import org.junit.Test; -import ch.eitchnet.utils.dbc.DBC; - public class FlushTxTest extends AbstractRealmServiceTest { @Test diff --git a/li.strolch.service/src/test/java/li/strolch/service/TxTest.java b/li.strolch.service/src/test/java/li/strolch/service/TxTest.java index ee9ef3e25..99a2ba526 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/TxTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/TxTest.java @@ -26,12 +26,11 @@ import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceArgument; import li.strolch.service.api.ServiceResult; import li.strolch.service.test.AbstractRealmServiceTest; +import li.strolch.utils.dbc.DBC; import org.junit.Ignore; import org.junit.Test; -import ch.eitchnet.utils.dbc.DBC; - public class TxTest extends AbstractRealmServiceTest { @Test diff --git a/li.strolch.service/src/test/java/li/strolch/service/test/AbstractRealmServiceTest.java b/li.strolch.service/src/test/java/li/strolch/service/test/AbstractRealmServiceTest.java index edb419b22..fc0816869 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/test/AbstractRealmServiceTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/test/AbstractRealmServiceTest.java @@ -27,12 +27,11 @@ import org.postgresql.Driver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.db.DbSchemaVersionCheck; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.Version; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchRealm; +import li.strolch.db.DbSchemaVersionCheck; import li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler; +import li.strolch.privilege.model.Certificate; import li.strolch.service.XmlImportModelArgument; import li.strolch.service.XmlImportModelResult; import li.strolch.service.XmlImportModelService; @@ -42,6 +41,7 @@ import li.strolch.service.api.ServiceHandler; import li.strolch.service.api.ServiceResult; import li.strolch.service.api.ServiceResultState; import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.Version; /** * @author Robert von Burg diff --git a/li.strolch.service/src/test/java/li/strolch/service/test/GreetingServiceTest.java b/li.strolch.service/src/test/java/li/strolch/service/test/GreetingServiceTest.java index ae9f2c278..5c3dec1ba 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/test/GreetingServiceTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/test/GreetingServiceTest.java @@ -17,14 +17,14 @@ package li.strolch.service.test; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; + +import li.strolch.privilege.model.Certificate; import li.strolch.service.test.model.GreetingResult; import li.strolch.service.test.model.GreetingService; import li.strolch.service.test.model.GreetingService.GreetingArgument; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; - /** * @author Robert von Burg */ diff --git a/li.strolch.service/src/test/java/li/strolch/service/test/LockingTest.java b/li.strolch.service/src/test/java/li/strolch/service/test/LockingTest.java index 6e952b041..fd1577d37 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/test/LockingTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/test/LockingTest.java @@ -28,10 +28,10 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; import li.strolch.model.Locator; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceArgument; import li.strolch.service.api.ServiceHandler; diff --git a/li.strolch.service/src/test/java/li/strolch/service/test/ServiceTest.java b/li.strolch.service/src/test/java/li/strolch/service/test/ServiceTest.java index 601d6d495..c730704da 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/test/ServiceTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/test/ServiceTest.java @@ -27,10 +27,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import ch.eitchnet.privilege.base.AccessDeniedException; -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.privilege.model.UserState; +import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.PrivilegeException; +import li.strolch.privilege.model.Certificate; +import li.strolch.privilege.model.UserState; import li.strolch.service.api.ServiceResult; import li.strolch.service.test.model.GreetingResult; import li.strolch.service.test.model.GreetingService; diff --git a/li.strolch.service/src/test/java/li/strolch/service/test/XmlExportServiceTest.java b/li.strolch.service/src/test/java/li/strolch/service/test/XmlExportServiceTest.java index c8699c5c8..6e42318ce 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/test/XmlExportServiceTest.java +++ b/li.strolch.service/src/test/java/li/strolch/service/test/XmlExportServiceTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import java.io.File; import java.io.FilenameFilter; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.service.XmlExportModelArgument; import li.strolch.service.XmlExportModelService; @@ -34,8 +35,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import ch.eitchnet.privilege.model.Certificate; - /** * @author Robert von Burg */ diff --git a/li.strolch.service/src/test/java/li/strolch/service/test/model/GreetingService.java b/li.strolch.service/src/test/java/li/strolch/service/test/model/GreetingService.java index 656d53abe..df7f331a7 100644 --- a/li.strolch.service/src/test/java/li/strolch/service/test/model/GreetingService.java +++ b/li.strolch.service/src/test/java/li/strolch/service/test/model/GreetingService.java @@ -20,7 +20,7 @@ import java.text.MessageFormat; import li.strolch.service.api.AbstractService; import li.strolch.service.api.ServiceArgument; import li.strolch.service.test.model.GreetingService.GreetingArgument; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/li.strolch.service/src/test/resources/log4j.xml b/li.strolch.service/src/test/resources/log4j.xml index 0a2a73d06..7a0499275 100644 --- a/li.strolch.service/src/test/resources/log4j.xml +++ b/li.strolch.service/src/test/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeConfig.xml b/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeConfig.xml +++ b/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeRoles.xml b/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeRoles.xml index 114bbe099..f032d7ffe 100644 --- a/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeRoles.xml +++ b/li.strolch.service/src/test/resources/migrationstest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms li.strolch.migrations.QueryCurrentVersionsAction li.strolch.migrations.RunMigrationsAction diff --git a/li.strolch.service/src/test/resources/svctest/config/PrivilegeConfig.xml b/li.strolch.service/src/test/resources/svctest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.service/src/test/resources/svctest/config/PrivilegeConfig.xml +++ b/li.strolch.service/src/test/resources/svctest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.service/src/test/resources/svctest/config/PrivilegeRoles.xml b/li.strolch.service/src/test/resources/svctest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.service/src/test/resources/svctest/config/PrivilegeRoles.xml +++ b/li.strolch.service/src/test/resources/svctest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.service/src/test/resources/transienttest/config/PrivilegeConfig.xml b/li.strolch.service/src/test/resources/transienttest/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.service/src/test/resources/transienttest/config/PrivilegeConfig.xml +++ b/li.strolch.service/src/test/resources/transienttest/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.service/src/test/resources/transienttest/config/PrivilegeRoles.xml b/li.strolch.service/src/test/resources/transienttest/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.service/src/test/resources/transienttest/config/PrivilegeRoles.xml +++ b/li.strolch.service/src/test/resources/transienttest/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml b/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml index 2faba827e..cfab85b24 100644 --- a/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml +++ b/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,9 +24,9 @@ - - - + + + \ No newline at end of file diff --git a/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml b/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml index 207e89bc0..3a412fb38 100644 --- a/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml +++ b/li.strolch.service/src/test/resources/withPrivilegeRuntime/config/PrivilegeRoles.xml @@ -2,7 +2,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.testbase/pom.xml b/li.strolch.testbase/pom.xml index 4c0883101..fa537095e 100644 --- a/li.strolch.testbase/pom.xml +++ b/li.strolch.testbase/pom.xml @@ -1,34 +1,20 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.testbase - li.strolch.testbase runtime for Strolch - - https://github.com/eitchnet/li.strolch.testbase - 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.testbase/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java index 294016477..6abb15e7f 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java @@ -16,6 +16,7 @@ package li.strolch.testbase.runtime; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; @@ -23,8 +24,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; - public abstract class AbstractModelTest { protected static final Logger logger = LoggerFactory.getLogger(AbstractModelTest.class); diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AuditModelTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AuditModelTestRunner.java index 20f14e66d..32591ca8f 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AuditModelTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AuditModelTestRunner.java @@ -33,9 +33,9 @@ import li.strolch.agent.api.StrolchRealm; import li.strolch.model.ModelGenerator; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.collections.DateRange; +import li.strolch.utils.collections.DateRange; /** * @author Robert von Burg diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java index db5bee2e8..ffd2af630 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java @@ -36,8 +36,8 @@ import li.strolch.agent.impl.DataStoreMode; import li.strolch.model.Order; import li.strolch.model.parameter.Parameter; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; @SuppressWarnings("nls") public class OrderModelTestRunner { diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java index d2dc212d3..fa259f29b 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java @@ -36,8 +36,8 @@ import li.strolch.agent.impl.DataStoreMode; import li.strolch.model.Resource; import li.strolch.model.parameter.Parameter; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; @SuppressWarnings("nls") public class ResourceModelTestRunner { diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/RuntimeMock.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/RuntimeMock.java index c9f5a183c..25e9f35d3 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/RuntimeMock.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/RuntimeMock.java @@ -26,20 +26,20 @@ import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.privilege.model.Certificate; -import ch.eitchnet.utils.helper.FileHelper; -import ch.eitchnet.utils.helper.StringHelper; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchAgent; import li.strolch.agent.api.StrolchBootstrapper; import li.strolch.agent.api.StrolchRealm; import li.strolch.agent.api.StrolchVersion; +import li.strolch.privilege.model.Certificate; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.service.api.Service; import li.strolch.service.api.ServiceArgument; import li.strolch.service.api.ServiceHandler; import li.strolch.service.api.ServiceResult; import li.strolch.service.api.ServiceResultState; +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; public final class RuntimeMock { diff --git a/li.strolch.tutorialapp/pom.xml b/li.strolch.tutorialapp/pom.xml index 71ec41c6a..7094ddff3 100644 --- a/li.strolch.tutorialapp/pom.xml +++ b/li.strolch.tutorialapp/pom.xml @@ -1,34 +1,20 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml li.strolch.tutorialapp - li.strolch.tutorialapp Tutorial Application for Strolch - - https://github.com/eitchnet/li.strolch.tutorialapp - 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.tutorialapp/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - @@ -41,11 +27,6 @@ - - li.strolch - li.strolch.bom - pom - li.strolch li.strolch.persistence.xml diff --git a/li.strolch.tutorialapp/src/main/resources/log4j.xml b/li.strolch.tutorialapp/src/main/resources/log4j.xml index 1d2f3b080..c886d766d 100644 --- a/li.strolch.tutorialapp/src/main/resources/log4j.xml +++ b/li.strolch.tutorialapp/src/main/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.tutorialapp/src/runtime/config/PrivilegeConfig.xml b/li.strolch.tutorialapp/src/runtime/config/PrivilegeConfig.xml index 706602750..aaf42b2c6 100644 --- a/li.strolch.tutorialapp/src/runtime/config/PrivilegeConfig.xml +++ b/li.strolch.tutorialapp/src/runtime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,7 +24,7 @@ - + \ No newline at end of file diff --git a/li.strolch.tutorialapp/src/runtime/config/PrivilegeRoles.xml b/li.strolch.tutorialapp/src/runtime/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.tutorialapp/src/runtime/config/PrivilegeRoles.xml +++ b/li.strolch.tutorialapp/src/runtime/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.tutorialwebapp/pom.xml b/li.strolch.tutorialwebapp/pom.xml index f33cf9ac5..b13eb1ee6 100644 --- a/li.strolch.tutorialwebapp/pom.xml +++ b/li.strolch.tutorialwebapp/pom.xml @@ -1,14 +1,21 @@ - + 4.0.0 li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml + li.strolch.tutorialwebapp + li.strolch.tutorialwebapp + Tutorial webapp to show case using Strolch in a servlet container + war + 2011 + UTF-8 tutorialwebapp @@ -17,44 +24,8 @@ ${warFinalName} - li.strolch.tutorialwebapp - li.strolch.tutorialwebapp - Tutorial webapp to show case using Strolch in a servlet container - war - - https://github.com/eitchnet/li.strolch.tutorialwebapp - - 2011 - - - Github Issues - https://github.com/eitchnet/li.strolch.tutorialwebapp/issues - - - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - - - - - li.strolch - li.strolch.bom - pom - ${project.version} - - - - - - li.strolch - li.strolch.bom - pom - li.strolch li.strolch.rest diff --git a/li.strolch.tutorialwebapp/src/main/resources/log4j.xml b/li.strolch.tutorialwebapp/src/main/resources/log4j.xml index 6bb2f5090..86ea6fcdf 100644 --- a/li.strolch.tutorialwebapp/src/main/resources/log4j.xml +++ b/li.strolch.tutorialwebapp/src/main/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml b/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml index 706602750..aaf42b2c6 100644 --- a/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml +++ b/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,7 +24,7 @@ - + \ No newline at end of file diff --git a/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml b/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml index bff38da9f..3a9e8ab07 100644 --- a/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml +++ b/li.strolch.tutorialwebapp/src/main/webapp/WEB-INF/config/PrivilegeRoles.xml @@ -1,7 +1,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/li.strolch.utils/.gitignore b/li.strolch.utils/.gitignore new file mode 100644 index 000000000..0f44a0f25 --- /dev/null +++ b/li.strolch.utils/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.classpath diff --git a/li.strolch.utils/LICENSE b/li.strolch.utils/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/li.strolch.utils/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/li.strolch.utils/README.md b/li.strolch.utils/README.md new file mode 100644 index 000000000..76345938f --- /dev/null +++ b/li.strolch.utils/README.md @@ -0,0 +1,47 @@ +li.strolch.utils +====================== + +[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=li.strolch.utils)](http://jenkins.eitchnet.ch/view/li.strolch/job/li.strolch.utils/) + +Java Utilites which ease daily work when programming in the Java language + +Dependencies +---------------------- +This utility package is built by Maven3 and has very few external dependencies. The current dependencies are: +* the Java Runtime Environment 7 +* JUnit 4.11 (test scope) +* slf4j 1.7.2 +* slf4j-log4j bindings (test scope) + +Features +---------------------- +* RMI File client/server + * This is a small RMI client server which allows to fetch files from a server which exposes the RmiFileHandler class via RMI +* ObjectFilter + * The ObjectFilter allows to keep track of modifications to objects. The modifications are add/update/remove. + * You register the modification of an object on the filter and when all is done, you query the filter for all the add/update/remove modifications so that you only persist the required changes to your database +* ArraysHelper + * The ArraysHelper contains methods to handling arrays +* BaseEncoding + * The BaseEncoding class implements RFC4648 and thus implements Base64, Base32, Base16 in all their different alphabets and also implementes the D-Base32 encoding +* ByteHelper + * The ByteHelper contains methods to print, convert and manipulate bytes +* FileHelper + * The FileHelper contains methods relevant to files. E.g. recursively deleting directories, copying files, reading/writing files etc. +* ProcessHelper + * The ProcessHelper abstracts away OS specific process tasks +* StringHelper + * The StringHelper contains methods for handling Strings +* SystemHelper + * The SystemHelper contains methods to get system specific information +* XmlHelper + * The XmlHelper contains methods to handle XML files + +Building +------------------------- +* Prerequisites: + * JDK 6 is installed and JAVA_HOME is properly set and ../bin is in path + * Maven 3 is installed and MAVEN_HOME is properly set and ../bin is in path +* Clone repository and change path to root +* Run maven: + * mvn clean install diff --git a/li.strolch.utils/pom.xml b/li.strolch.utils/pom.xml new file mode 100644 index 000000000..380f71a2b --- /dev/null +++ b/li.strolch.utils/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + li.strolch + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml + + + li.strolch.utils + jar + li.strolch.utils + These utils contain project independent helper classes and utilities for reuse + 2011 + + + + org.slf4j + slf4j-api + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-site-plugin + + + + org.apache.maven.plugins + maven-deploy-plugin + + + + diff --git a/li.strolch.utils/src/main/java/javanet/staxutils/Indentation.java b/li.strolch.utils/src/main/java/javanet/staxutils/Indentation.java new file mode 100644 index 000000000..844513789 --- /dev/null +++ b/li.strolch.utils/src/main/java/javanet/staxutils/Indentation.java @@ -0,0 +1,36 @@ +package javanet.staxutils; + +/** + * Characters that represent line breaks and indentation. These are represented as String-valued JavaBean properties. + */ +@SuppressWarnings("nls") +public interface Indentation { + + /** Two spaces; the default indentation. */ + public static final String DEFAULT_INDENT = " "; + + /** + * Set the characters used for one level of indentation. The default is {@link #DEFAULT_INDENT}. "\t" is a popular + * alternative. + */ + void setIndent(String indent); + + /** The characters used for one level of indentation. */ + String getIndent(); + + /** + * "\n"; the normalized representation of end-of-line in XML. + */ + public static final String NORMAL_END_OF_LINE = "\n"; + + /** + * Set the characters that introduce a new line. The default is {@link #NORMAL_END_OF_LINE}. + * {@link IndentingXMLStreamWriter#getLineSeparator}() is a popular alternative. + */ + public void setNewLine(String newLine); + + /** The characters that introduce a new line. */ + String getNewLine(); + +} diff --git a/li.strolch.utils/src/main/java/javanet/staxutils/IndentingXMLStreamWriter.java b/li.strolch.utils/src/main/java/javanet/staxutils/IndentingXMLStreamWriter.java new file mode 100644 index 000000000..f4af62c62 --- /dev/null +++ b/li.strolch.utils/src/main/java/javanet/staxutils/IndentingXMLStreamWriter.java @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2006, John Kristian + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of StAX-Utils nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package javanet.staxutils; + +import javanet.staxutils.helpers.StreamWriterDelegate; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** + * A filter that indents an XML stream. To apply it, construct a filter that contains another {@link XMLStreamWriter}, + * which you pass to the constructor. Then call methods of the filter instead of the contained stream. For example: + * + *
+ * {@link XMLStreamWriter} stream = ...
+ * stream = new {@link IndentingXMLStreamWriter}(stream);
+ * stream.writeStartDocument();
+ * ...
+ * 
+ * + *

+ * The filter inserts characters to format the document as an outline, with nested elements indented. Basically, it + * inserts a line break and whitespace before: + *

    + *
  • each DTD, processing instruction or comment that's not preceded by data
  • + *
  • each starting tag that's not preceded by data
  • + *
  • each ending tag that's preceded by nested elements but not data
  • + *
+ * This works well with 'data-oriented' XML, wherein each element contains either data or nested elements but not both. + * It can work badly with other styles of XML. For example, the data in a 'mixed content' document are apt to be + * polluted with indentation characters. + *

+ * Indentation can be adjusted by setting the newLine and indent properties. But set them to whitespace only, for best + * results. Non-whitespace is apt to cause problems, for example when this class attempts to insert newLine before the + * root element. + * + * @author John Kristian + */ +@SuppressWarnings("nls") +public class IndentingXMLStreamWriter extends StreamWriterDelegate implements Indentation { + + public IndentingXMLStreamWriter(XMLStreamWriter out) { + this(out, DEFAULT_INDENT, NORMAL_END_OF_LINE); + } + + public IndentingXMLStreamWriter(XMLStreamWriter out, String indent) { + this(out, indent, NORMAL_END_OF_LINE); + } + + public IndentingXMLStreamWriter(XMLStreamWriter out, String indent, String newLine) { + super(out); + setIndent(indent); + setNewLine(newLine); + } + + /** How deeply nested the current scope is. The root element is depth 1. */ + private int depth = 0; // document scope + + /** stack[depth] indicates what's been written into the current scope. */ + private int[] stack = new int[] { 0, 0, 0, 0 }; // nothing written yet + + private static final int WROTE_MARKUP = 1; + + private static final int WROTE_DATA = 2; + + private String indent = DEFAULT_INDENT; + + private String newLine = NORMAL_END_OF_LINE; + + /** newLine followed by copies of indent. */ + private char[] linePrefix = null; + + @Override + public void setIndent(String indent) { + if (!indent.equals(this.indent)) { + this.indent = indent; + this.linePrefix = null; + } + } + + @Override + public String getIndent() { + return this.indent; + } + + @Override + public void setNewLine(String newLine) { + if (!newLine.equals(this.newLine)) { + this.newLine = newLine; + this.linePrefix = null; + } + } + + /** + * @return System.getProperty("line.separator"); or {@link #NORMAL_END_OF_LINE} if that fails. + */ + public static String getLineSeparator() { + try { + return System.getProperty("line.separator"); + } catch (SecurityException ignored) { + // + } + return NORMAL_END_OF_LINE; + } + + @Override + public String getNewLine() { + return this.newLine; + } + + @Override + public void writeStartDocument() throws XMLStreamException { + beforeMarkup(); + this.out.writeStartDocument(); + afterMarkup(); + } + + @Override + public void writeStartDocument(String version) throws XMLStreamException { + beforeMarkup(); + this.out.writeStartDocument(version); + afterMarkup(); + } + + @Override + public void writeStartDocument(String encoding, String version) throws XMLStreamException { + beforeMarkup(); + this.out.writeStartDocument(encoding, version); + afterMarkup(); + } + + @Override + public void writeDTD(String dtd) throws XMLStreamException { + beforeMarkup(); + this.out.writeDTD(dtd); + afterMarkup(); + } + + @Override + public void writeProcessingInstruction(String target) throws XMLStreamException { + beforeMarkup(); + this.out.writeProcessingInstruction(target); + afterMarkup(); + } + + @Override + public void writeProcessingInstruction(String target, String data) throws XMLStreamException { + beforeMarkup(); + this.out.writeProcessingInstruction(target, data); + afterMarkup(); + } + + @Override + public void writeComment(String data) throws XMLStreamException { + beforeMarkup(); + this.out.writeComment(data); + afterMarkup(); + } + + @Override + public void writeEmptyElement(String localName) throws XMLStreamException { + beforeMarkup(); + this.out.writeEmptyElement(localName); + afterMarkup(); + } + + @Override + public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { + beforeMarkup(); + this.out.writeEmptyElement(namespaceURI, localName); + afterMarkup(); + } + + @Override + public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + beforeMarkup(); + this.out.writeEmptyElement(prefix, localName, namespaceURI); + afterMarkup(); + } + + @Override + public void writeStartElement(String localName) throws XMLStreamException { + beforeStartElement(); + this.out.writeStartElement(localName); + afterStartElement(); + } + + @Override + public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { + beforeStartElement(); + this.out.writeStartElement(namespaceURI, localName); + afterStartElement(); + } + + @Override + public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + beforeStartElement(); + this.out.writeStartElement(prefix, localName, namespaceURI); + afterStartElement(); + } + + @Override + public void writeCharacters(String text) throws XMLStreamException { + this.out.writeCharacters(text); + afterData(); + } + + @Override + public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { + this.out.writeCharacters(text, start, len); + afterData(); + } + + @Override + public void writeCData(String data) throws XMLStreamException { + this.out.writeCData(data); + afterData(); + } + + @Override + public void writeEntityRef(String name) throws XMLStreamException { + this.out.writeEntityRef(name); + afterData(); + } + + @Override + public void writeEndElement() throws XMLStreamException { + beforeEndElement(); + this.out.writeEndElement(); + afterEndElement(); + } + + @Override + public void writeEndDocument() throws XMLStreamException { + try { + while (this.depth > 0) { + writeEndElement(); // indented + } + } catch (Exception ignored) { + ignored.printStackTrace(); + } + this.out.writeEndDocument(); + afterEndDocument(); + } + + /** Prepare to write markup, by writing a new line and indentation. */ + protected void beforeMarkup() { + int soFar = this.stack[this.depth]; + if ((soFar & WROTE_DATA) == 0 // no data in this scope + && (this.depth > 0 || soFar != 0)) // not the first line + { + try { + writeNewLine(this.depth); + if (this.depth > 0 && getIndent().length() > 0) { + afterMarkup(); // indentation was written + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** Note that markup or indentation was written. */ + protected void afterMarkup() { + this.stack[this.depth] |= WROTE_MARKUP; + } + + /** Note that data were written. */ + protected void afterData() { + this.stack[this.depth] |= WROTE_DATA; + } + + /** Prepare to start an element, by allocating stack space. */ + protected void beforeStartElement() { + beforeMarkup(); + if (this.stack.length <= this.depth + 1) { + // Allocate more space for the stack: + int[] newStack = new int[this.stack.length * 2]; + System.arraycopy(this.stack, 0, newStack, 0, this.stack.length); + this.stack = newStack; + } + this.stack[this.depth + 1] = 0; // nothing written yet + } + + /** Note that an element was started. */ + protected void afterStartElement() { + afterMarkup(); + ++this.depth; + } + + /** Prepare to end an element, by writing a new line and indentation. */ + protected void beforeEndElement() { + if (this.depth > 0 && this.stack[this.depth] == WROTE_MARKUP) { // but not data + try { + writeNewLine(this.depth - 1); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + } + + /** Note that an element was ended. */ + protected void afterEndElement() { + if (this.depth > 0) { + --this.depth; + } + } + + /** Note that a document was ended. */ + protected void afterEndDocument() { + if (this.stack[this.depth = 0] == WROTE_MARKUP) { // but not data + try { + writeNewLine(0); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + this.stack[this.depth] = 0; // start fresh + } + + /** Write a line separator followed by indentation. */ + protected void writeNewLine(int indentation) throws XMLStreamException { + final int newLineLength = getNewLine().length(); + final int prefixLength = newLineLength + (getIndent().length() * indentation); + if (prefixLength > 0) { + if (this.linePrefix == null) { + this.linePrefix = (getNewLine() + getIndent()).toCharArray(); + } + while (prefixLength > this.linePrefix.length) { + // make linePrefix longer: + char[] newPrefix = new char[newLineLength + ((this.linePrefix.length - newLineLength) * 2)]; + System.arraycopy(this.linePrefix, 0, newPrefix, 0, this.linePrefix.length); + System.arraycopy(this.linePrefix, newLineLength, newPrefix, this.linePrefix.length, + this.linePrefix.length - newLineLength); + this.linePrefix = newPrefix; + } + this.out.writeCharacters(this.linePrefix, 0, prefixLength); + } + } + +} diff --git a/li.strolch.utils/src/main/java/javanet/staxutils/helpers/StreamWriterDelegate.java b/li.strolch.utils/src/main/java/javanet/staxutils/helpers/StreamWriterDelegate.java new file mode 100644 index 000000000..9922aafa7 --- /dev/null +++ b/li.strolch.utils/src/main/java/javanet/staxutils/helpers/StreamWriterDelegate.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2006, John Kristian + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of StAX-Utils nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package javanet.staxutils.helpers; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** + * Abstract class for writing filtered XML streams. This class provides methods that merely delegate to the contained + * stream. Subclasses should override some of these methods, and may also provide additional methods and fields. + * + * @author John Kristian + */ +public abstract class StreamWriterDelegate implements XMLStreamWriter { + + protected StreamWriterDelegate(XMLStreamWriter out) { + this.out = out; + } + + protected XMLStreamWriter out; + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + return this.out.getProperty(name); + } + + @Override + public NamespaceContext getNamespaceContext() { + return this.out.getNamespaceContext(); + } + + @Override + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + this.out.setNamespaceContext(context); + } + + @Override + public void setDefaultNamespace(String uri) throws XMLStreamException { + this.out.setDefaultNamespace(uri); + } + + @Override + public void writeStartDocument() throws XMLStreamException { + this.out.writeStartDocument(); + } + + @Override + public void writeStartDocument(String version) throws XMLStreamException { + this.out.writeStartDocument(version); + } + + @Override + public void writeStartDocument(String encoding, String version) throws XMLStreamException { + this.out.writeStartDocument(encoding, version); + } + + @Override + public void writeDTD(String dtd) throws XMLStreamException { + this.out.writeDTD(dtd); + } + + @Override + public void writeProcessingInstruction(String target) throws XMLStreamException { + this.out.writeProcessingInstruction(target); + } + + @Override + public void writeProcessingInstruction(String target, String data) throws XMLStreamException { + this.out.writeProcessingInstruction(target, data); + } + + @Override + public void writeComment(String data) throws XMLStreamException { + this.out.writeComment(data); + } + + @Override + public void writeEmptyElement(String localName) throws XMLStreamException { + this.out.writeEmptyElement(localName); + } + + @Override + public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { + this.out.writeEmptyElement(namespaceURI, localName); + } + + @Override + public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + this.out.writeEmptyElement(prefix, localName, namespaceURI); + } + + @Override + public void writeStartElement(String localName) throws XMLStreamException { + this.out.writeStartElement(localName); + } + + @Override + public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { + this.out.writeStartElement(namespaceURI, localName); + } + + @Override + public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + this.out.writeStartElement(prefix, localName, namespaceURI); + } + + @Override + public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException { + this.out.writeDefaultNamespace(namespaceURI); + } + + @Override + public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { + this.out.writeNamespace(prefix, namespaceURI); + } + + @Override + public String getPrefix(String uri) throws XMLStreamException { + return this.out.getPrefix(uri); + } + + @Override + public void setPrefix(String prefix, String uri) throws XMLStreamException { + this.out.setPrefix(prefix, uri); + } + + @Override + public void writeAttribute(String localName, String value) throws XMLStreamException { + this.out.writeAttribute(localName, value); + } + + @Override + public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { + this.out.writeAttribute(namespaceURI, localName, value); + } + + @Override + public void writeAttribute(String prefix, String namespaceURI, String localName, String value) + throws XMLStreamException { + this.out.writeAttribute(prefix, namespaceURI, localName, value); + } + + @Override + public void writeCharacters(String text) throws XMLStreamException { + this.out.writeCharacters(text); + } + + @Override + public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { + this.out.writeCharacters(text, start, len); + } + + @Override + public void writeCData(String data) throws XMLStreamException { + this.out.writeCData(data); + } + + @Override + public void writeEntityRef(String name) throws XMLStreamException { + this.out.writeEntityRef(name); + } + + @Override + public void writeEndElement() throws XMLStreamException { + this.out.writeEndElement(); + } + + @Override + public void writeEndDocument() throws XMLStreamException { + this.out.writeEndDocument(); + } + + @Override + public void flush() throws XMLStreamException { + this.out.flush(); + } + + @Override + public void close() throws XMLStreamException { + this.out.close(); + } + +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/CommandKey.java b/li.strolch.utils/src/main/java/li/strolch/communication/CommandKey.java new file mode 100644 index 000000000..a0f5eff3a --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/CommandKey.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +public class CommandKey { + private final String key1; + private final String key2; + private final int hashCode; + + /** + * @param key1 + * @param key2 + */ + public CommandKey(String key1, String key2) { + this.key1 = key1; + this.key2 = key2; + + final int prime = 31; + int result = 1; + result = prime * result + ((this.key1 == null) ? 0 : this.key1.hashCode()); + result = prime * result + ((this.key2 == null) ? 0 : this.key2.hashCode()); + this.hashCode = result; + } + + public static CommandKey key(String key1, String key2) { + return new CommandKey(key1, key2); + } + + @Override + public int hashCode() { + return this.hashCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CommandKey other = (CommandKey) obj; + return this.key1.equals(other.key1) && this.key2.equals(other.key2); + } + + @Override + public String toString() { + return this.key1 + StringHelper.COLON + this.key2; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/CommunicationConnection.java b/li.strolch.utils/src/main/java/li/strolch/communication/CommunicationConnection.java new file mode 100644 index 000000000..770f0de66 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/CommunicationConnection.java @@ -0,0 +1,405 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.LinkedBlockingDeque; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.IoMessage.State; +import li.strolch.utils.collections.MapOfLists; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +public class CommunicationConnection implements Runnable { + + protected static final Logger logger = LoggerFactory.getLogger(CommunicationConnection.class); + + private String id; + private ConnectionMode mode; + private Map parameters; + + private ConnectionState state; + private String stateMsg; + + private BlockingDeque messageQueue; + private Thread queueThread; + private volatile boolean run; + private MapOfLists connectionObservers; + private List connectionStateObservers; + + private CommunicationEndpoint endpoint; + private IoMessageVisitor messageVisitor; + + private IoMessageArchive archive; + + public CommunicationConnection(String id, ConnectionMode mode, Map parameters, + CommunicationEndpoint endpoint, IoMessageVisitor messageVisitor) { + + DBC.PRE.assertNotEmpty("Id must be set!", id); //$NON-NLS-1$ + DBC.PRE.assertNotNull("ConnectionMode must be set!", mode); //$NON-NLS-1$ + DBC.PRE.assertNotNull("Paramerters must not be null!", parameters); //$NON-NLS-1$ + DBC.PRE.assertNotNull("Endpoint must be set!", endpoint); //$NON-NLS-1$ + DBC.PRE.assertNotNull("IoMessageVisitor must be set!", messageVisitor); //$NON-NLS-1$ + + this.id = id; + this.mode = mode; + this.parameters = parameters; + this.endpoint = endpoint; + this.messageVisitor = messageVisitor; + + this.state = ConnectionState.CREATED; + this.stateMsg = this.state.toString(); + this.messageQueue = new LinkedBlockingDeque<>(); + this.connectionObservers = new MapOfLists<>(); + this.connectionStateObservers = new ArrayList<>(); + } + + public void setArchive(IoMessageArchive archive) { + this.archive = archive; + } + + public IoMessageArchive getArchive() { + return this.archive; + } + + public String getId() { + return this.id; + } + + public int getQueueSize() { + return this.messageQueue.size(); + } + + public ConnectionState getState() { + return this.state; + } + + public String getStateMsg() { + return this.stateMsg; + } + + public ConnectionMode getMode() { + return this.mode; + } + + public Map getParameters() { + return this.parameters; + } + + public void clearQueue() { + this.messageQueue.clear(); + } + + public void addConnectionObserver(CommandKey key, ConnectionObserver observer) { + synchronized (this.connectionObservers) { + this.connectionObservers.addElement(key, observer); + } + } + + public void removeConnectionObserver(CommandKey key, ConnectionObserver observer) { + synchronized (this.connectionObservers) { + this.connectionObservers.removeElement(key, observer); + } + } + + public void addConnectionStateObserver(ConnectionStateObserver observer) { + synchronized (this.connectionStateObservers) { + this.connectionStateObservers.add(observer); + } + } + + public void removeConnectionStateObserver(ConnectionStateObserver observer) { + synchronized (this.connectionStateObservers) { + this.connectionStateObservers.remove(observer); + } + } + + public void notifyStateChange(ConnectionState state, String stateMsg) { + ConnectionState oldState = this.state; + String oldStateMsg = this.stateMsg; + this.state = state; + this.stateMsg = stateMsg; + + List observers; + synchronized (this.connectionStateObservers) { + observers = new ArrayList<>(this.connectionStateObservers); + } + for (ConnectionStateObserver observer : observers) { + observer.notify(oldState, oldStateMsg, state, stateMsg); + } + } + + public void switchMode(ConnectionMode mode) { + ConnectionMessages.assertConfigured(this, "Can not switch modes yet!"); //$NON-NLS-1$ + if (mode == ConnectionMode.OFF) { + stop(); + } else if (mode == ConnectionMode.ON) { + stop(); + start(); + } + + this.mode = mode; + } + + /** + * Configure the underlying {@link CommunicationEndpoint} and {@link IoMessageVisitor} + */ + public void configure() { + this.messageVisitor.configure(this); + this.endpoint.configure(this, this.messageVisitor); + notifyStateChange(ConnectionState.INITIALIZED, ConnectionState.INITIALIZED.name()); + } + + public void start() { + ConnectionMessages.assertConfigured(this, "Can not start yet!"); //$NON-NLS-1$ + + switch (this.mode) { + case OFF: + logger.info("Not connecting as mode is currently OFF"); //$NON-NLS-1$ + break; + case SIMULATION: + logger.info("Started SIMULATION connection!"); //$NON-NLS-1$ + break; + case ON: + if (this.queueThread != null) { + logger.warn(MessageFormat.format("{0}: Already connected!", this.id)); //$NON-NLS-1$ + } else { + logger.info(MessageFormat.format("Starting Connection {0} to {1}...", this.id, getRemoteUri())); //$NON-NLS-1$ + this.run = true; + this.queueThread = new Thread(this, MessageFormat.format("{0}_OUT", this.id)); //$NON-NLS-1$ + this.queueThread.start(); + + connectEndpoint(); + } + break; + default: + logger.error("Unhandled mode " + this.mode); //$NON-NLS-1$ + break; + } + } + + public void stop() { + ConnectionMessages.assertConfigured(this, "Can not stop yet!"); //$NON-NLS-1$ + + switch (this.mode) { + case OFF: + break; + case SIMULATION: + logger.info("Disconnected SIMULATION connection!"); //$NON-NLS-1$ + break; + case ON: + logger.info("Disconnecting..."); //$NON-NLS-1$ + if (this.queueThread == null) { + logger.warn(MessageFormat.format("{0}: Already disconnected!", this.id)); //$NON-NLS-1$ + } else { + this.run = false; + + try { + disconnectEndpoint(); + } catch (Exception e) { + String msg = "Caught exception while disconnecting endpoint: {0}"; //$NON-NLS-1$ + logger.error(MessageFormat.format(msg, e.getLocalizedMessage()), e); + } + + try { + this.queueThread.interrupt(); + } catch (Exception e) { + String msg = "Caught exception while stopping queue thread: {0}"; //$NON-NLS-1$ + logger.warn(MessageFormat.format(msg, e.getLocalizedMessage())); + } + String msg = "{0} is stopped"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.queueThread.getName())); + this.queueThread = null; + } + break; + default: + logger.error("Unhandled mode " + this.mode); //$NON-NLS-1$ + break; + } + } + + /** + * Called by the underlying endpoint when a new message has been received and parsed + * + * @param message + */ + public void handleNewMessage(IoMessage message) { + ConnectionMessages.assertConfigured(this, "Can not be notified of new message yet!"); //$NON-NLS-1$ + + // if the state of the message is already later than ACCEPTED + // then an underlying component has already set the state, so + // we don't need to set it + if (message.getState().compareTo(State.ACCEPTED) < 0) + message.setState(State.ACCEPTED, StringHelper.DASH); + + notifyObservers(message); + } + + public void notifyObservers(IoMessage message) { + List observers; + synchronized (this.connectionObservers) { + List list = this.connectionObservers.getList(message.getKey()); + if (list == null) + return; + + observers = new ArrayList<>(list); + } + + for (ConnectionObserver observer : observers) { + try { + observer.notify(message.getKey(), message); + } catch (Exception e) { + String msg = "Failed to notify observer for key {0} on message with id {1}"; //$NON-NLS-1$ + logger.error(MessageFormat.format(msg, message.getKey(), message.getId()), e); + } + } + + if (this.archive != null) + this.archive.archive(message); + } + + @Override + public void run() { + while (this.run) { + + IoMessage message = null; + + try { + + message = this.messageQueue.take(); + logger.info(MessageFormat.format("Processing message {0}...", message.getId())); //$NON-NLS-1$ + + if (this.mode == ConnectionMode.ON) + this.endpoint.send(message); + else if (this.mode == ConnectionMode.SIMULATION) + this.endpoint.simulate(message); + + // notify the caller that the message has been processed + if (message.getState().compareTo(State.DONE) < 0) + message.setState(State.DONE, StringHelper.DASH); + + done(message); + + } catch (InterruptedException e) { + logger.warn(MessageFormat.format("{0} connection has been interruped!", this.id)); //$NON-NLS-1$ + + // an interrupted exception means the thread must stop + this.run = false; + + if (message != null) { + logger.error(MessageFormat.format("Can not send message {0}", message.getId())); //$NON-NLS-1$ + message.setState(State.FATAL, e.getLocalizedMessage()); + done(message); + } + + } catch (Exception e) { + logger.error(e.getMessage(), e); + + if (message != null) { + logger.error(MessageFormat.format("Can not send message {0}", message.getId())); //$NON-NLS-1$ + message.setState(State.FATAL, e.getLocalizedMessage()); + done(message); + } + } finally { + if (message != null && this.archive != null) { + this.archive.archive(message); + } + } + } + } + + /** + * Called when an outgoing message has been handled. This method logs the message state and then notifies all + * observers + * + * @param message + */ + public void done(IoMessage message) { + ConnectionMessages.assertConfigured(this, "Can not notify observers yet!"); //$NON-NLS-1$ + + switch (message.getState()) { + case ACCEPTED: + case CREATED: + case DONE: + case PENDING: + logger.info(MessageFormat.format("Sent message {0}", message.toString())); //$NON-NLS-1$ + break; + case FAILED: + case FATAL: + logger.error(MessageFormat.format("Failed to send message {0}", message.toString())); //$NON-NLS-1$ + break; + default: + logger.error(MessageFormat.format("Unhandled state for message {0}", message.toString())); //$NON-NLS-1$ + break; + } + + notifyObservers(message); + } + + public String getRemoteUri() { + return this.endpoint == null ? "0.0.0.0:0" : this.endpoint.getRemoteUri(); //$NON-NLS-1$ + } + + public String getLocalUri() { + return this.endpoint == null ? "0.0.0.0:0" : this.endpoint.getLocalUri(); //$NON-NLS-1$ + } + + public void reset() { + ConnectionMessages.assertConfigured(this, "Can not resest yet!"); //$NON-NLS-1$ + this.endpoint.reset(); + } + + /** + * Called when the connection is connected, thus the underlying endpoint can be started + */ + protected void connectEndpoint() { + this.endpoint.start(); + } + + /** + * Called when the connection is disconnected, thus the underlying endpoint must be stopped + */ + protected void disconnectEndpoint() { + this.endpoint.stop(); + } + + /** + * Send the message using the underlying endpoint. Do not change the state of the message, this will be done by the + * caller + * + * @param message + */ + public void send(IoMessage message) { + ConnectionMessages.assertConfigured(this, "Can not send yet"); //$NON-NLS-1$ + if (this.mode == ConnectionMode.OFF) + throw ConnectionMessages.throwNotConnected(this, message); + + message.setState(State.PENDING, State.PENDING.name()); + + this.messageQueue.add(message); + this.messageQueue.add(message); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/CommunicationEndpoint.java b/li.strolch.utils/src/main/java/li/strolch/communication/CommunicationEndpoint.java new file mode 100644 index 000000000..b56f9f12c --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/CommunicationEndpoint.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +/** + * @author Robert von Burg + */ +public interface CommunicationEndpoint { + + public void configure(CommunicationConnection connection, IoMessageVisitor converter); + + public void start(); + + public void stop(); + + public void reset(); + + public String getLocalUri(); + + public String getRemoteUri(); + + public void send(IoMessage message) throws Exception; + + public void simulate(IoMessage message) throws Exception; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionException.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionException.java new file mode 100644 index 000000000..2e92b0838 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionException.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +/** + * Base Exception for exceptions thrown by the communication classes + * + * @author Robert von Burg + */ +public class ConnectionException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public ConnectionException(String message, Throwable cause) { + super(message, cause); + } + + public ConnectionException(String message) { + super(message); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionInfo.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionInfo.java new file mode 100644 index 000000000..163081406 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionInfo.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012, Robert von Burg + * + * All rights reserved. + * + * This file is part of the XXX. + * + * XXX is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * XXX is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XXX. If not, see + * . + */ +package li.strolch.communication; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @author Robert von Burg + */ +@XmlRootElement(name = "ConnectionInfo") +@XmlAccessorType(XmlAccessType.FIELD) +public class ConnectionInfo { + + @XmlAttribute(name = "id") + private String id; + + @XmlAttribute(name = "localUri") + private String localUri; + + @XmlAttribute(name = "remoteUri") + private String remoteUri; + + @XmlAttribute(name = "mode") + private ConnectionMode mode; + + @XmlAttribute(name = "queueSize") + private int queueSize; + + @XmlAttribute(name = "state") + private ConnectionState state; + + @XmlAttribute(name = "stateMsg") + private String stateMsg; + + /** + * @return the id + */ + public String getId() { + return this.id; + } + + /** + * @param id + * the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the localUri + */ + public String getLocalUri() { + return this.localUri; + } + + /** + * @param localUri + * the localUri to set + */ + public void setLocalUri(String localUri) { + this.localUri = localUri; + } + + /** + * @return the remoteUri + */ + public String getRemoteUri() { + return this.remoteUri; + } + + /** + * @param remoteUri + * the remoteUri to set + */ + public void setRemoteUri(String remoteUri) { + this.remoteUri = remoteUri; + } + + /** + * @return the mode + */ + public ConnectionMode getMode() { + return this.mode; + } + + /** + * @param mode + * the mode to set + */ + public void setMode(ConnectionMode mode) { + this.mode = mode; + } + + /** + * @return the state + */ + public ConnectionState getState() { + return this.state; + } + + /** + * @param state + * the state to set + */ + public void setState(ConnectionState state) { + this.state = state; + } + + /** + * @return the stateMsg + */ + public String getStateMsg() { + return this.stateMsg; + } + + /** + * @param stateMsg + * the stateMsg to set + */ + public void setStateMsg(String stateMsg) { + this.stateMsg = stateMsg; + } + + /** + * @return the queueSize + */ + public int getQueueSize() { + return this.queueSize; + } + + /** + * @param queueSize + * the queueSize to set + */ + public void setQueueSize(int queueSize) { + this.queueSize = queueSize; + } + + public static ConnectionInfo valueOf(CommunicationConnection connection) { + ConnectionInfo info = new ConnectionInfo(); + info.setId(connection.getId()); + info.setLocalUri(connection.getLocalUri()); + info.setRemoteUri(connection.getRemoteUri()); + info.setMode(connection.getMode()); + info.setState(connection.getState()); + info.setStateMsg(connection.getStateMsg()); + info.setQueueSize(connection.getQueueSize()); + return info; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionMessages.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionMessages.java new file mode 100644 index 000000000..fd967b842 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionMessages.java @@ -0,0 +1,165 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.StringHelper; + +/** + * Helper class to thrown connection messages + * + * @author Robert von Burg + */ +public class ConnectionMessages { + + private static Logger logger = LoggerFactory.getLogger(ConnectionMessages.class); + + /** + * Utility class + */ + private ConnectionMessages() { + // + } + + /** + * Convenience method to throw an exception when an illegal {@link ConnectionState} change occurs + * + * @param current + * @param change + * + * @return + */ + public static ConnectionException throwIllegalConnectionState(ConnectionState current, ConnectionState change) { + String msg = "The connection with state {0} cannot be changed to {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, current.name(), change.name()); + ConnectionException e = new ConnectionException(msg); + return e; + } + + /** + * Convenience method to throw an exception when an invalid parameter is set in the configuration + * + * @param clazz + * @param parameterName + * @param parameterValue + * + * @return + */ + public static ConnectionException throwInvalidParameter(Class clazz, String parameterName, String parameterValue) { + String value; + if (parameterValue != null && !parameterValue.isEmpty()) + value = parameterValue; + else + value = StringHelper.NULL; + + String msg = "{0}: parameter ''{1}'' has invalid value ''{2}''"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, clazz.getSimpleName(), parameterName, value); + ConnectionException e = new ConnectionException(msg); + return e; + } + + /** + * Convenience method to throw an exception when an two conflicting parameters are activated + * + * @param clazz + * @param parameter1 + * @param parameter2 + * + * @return + */ + public static ConnectionException throwConflictingParameters(Class clazz, String parameter1, String parameter2) { + String msg = "{0} : The parameters {1} and {2} can not be both activated as they conflict"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, clazz.getSimpleName(), parameter1, parameter1); + ConnectionException e = new ConnectionException(msg); + return e; + } + + /** + * Convenience method to log a warning when a parameter is not set in the configuration + * + * @param clazz + * @param parameterName + * @param defValue + */ + public static void warnUnsetParameter(Class clazz, String parameterName, String defValue) { + if (logger.isDebugEnabled()) { + String msg = "{0}: parameter ''{1}'' is not set, using default value ''{2}''"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, clazz.getSimpleName(), parameterName, defValue); + Map properties = new HashMap<>(); + logger.warn(MessageFormat.format(msg, properties)); + } + } + + /** + * Convenience method to throw an exception when the connection is not yet configured + * + * @param connection + * @param message + */ + public static void assertConfigured(CommunicationConnection connection, String message) { + if (connection.getState() == ConnectionState.CREATED) { + String msg = "{0} : Not yet configured: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, connection.getId(), message); + throw new ConnectionException(msg); + } + } + + /** + * Convenience method to throw an exception when the connection is not connected + * + * @param connection + * @param message + * + * @return + */ + public static ConnectionException throwNotConnected(CommunicationConnection connection, String message) { + String msg = "{0} : Not connected: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, connection.getId(), message); + ConnectionException e = new ConnectionException(msg); + return e; + } + + /** + * Convenience method to throw an exception when the connection is not connected + * + * @param connection + * @param message + * + * @return + */ + public static ConnectionException throwNotConnected(CommunicationConnection connection, IoMessage message) { + String msg = "{0} : Not connected, can not send message with id {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, connection.getId(), message.getId()); + ConnectionException e = new ConnectionException(msg); + return e; + } + + public static void assertLegalMessageVisitor(Class endpoint, + Class expectedVisitor, IoMessageVisitor actualVisitor) { + if (!(expectedVisitor.isAssignableFrom(actualVisitor.getClass()))) { + String msg = "{0} requires {1} but has received illegal type {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, endpoint.getName(), expectedVisitor.getName(), actualVisitor.getClass() + .getName()); + throw new ConnectionException(msg); + } + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionMode.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionMode.java new file mode 100644 index 000000000..5b313dde5 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionMode.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.io.IOException; + +/** + *

+ * The mode of an {@link CommunicationConnection} can be one of the following enum values. This makes it possible use + * the connection without starting connection and later starting the connection when required + *

+ * The modes have the following semantics: + *
    + *
  • OFF - the connection can only have states {@link ConnectionState#CREATED} and {@link ConnectionState#INITIALIZED} + * . Trying to use the connection will throw an exception
  • + *
  • ON - the connection can be used normally
  • + *
  • SIMULATION - the same as ON, with the difference that the connection should silently drop any work
  • + *
+ * + * @author Robert von Burg + */ +public enum ConnectionMode { + + /** + * Denotes that the {@link CommunicationConnection} is off. This means it cannot accept messages, process messages + * or do any other kind of work + */ + OFF { + @Override + public boolean isSimulation() { + return false; + } + }, + + /** + * Denotes that the {@link CommunicationConnection} is on. This means that the {@link CommunicationConnection} + * accepts and process messages. Any connections which need to be established will automatically be connected and + * re-established should an {@link IOException} occur + */ + ON { + @Override + public boolean isSimulation() { + return false; + } + }, + + /** + * Denotes that the {@link CommunicationConnection} is in simulation mode. Mostly this means that the + * {@link CommunicationConnection} accepts messages, but silently swallows them, instead of processing them + */ + SIMULATION { + @Override + public boolean isSimulation() { + return true; + } + }; + + /** + * @return true if the current mode is simulation, false otherwise + */ + public abstract boolean isSimulation(); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionObserver.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionObserver.java new file mode 100644 index 000000000..a19a60cd5 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionObserver.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +/** + * @author Robert von Burg + */ +public interface ConnectionObserver { + + public void notify(CommandKey key, IoMessage message); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionState.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionState.java new file mode 100644 index 000000000..d0f34939e --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionState.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +/** + *

+ * a {@link CommunicationConnection} undergoes a serious of state changes. These states can be viewed by a client to + * monitor the state of the connection + *

+ * The states have the following semantics: + *
    + *
  • CREATED - initial state
  • + *
  • INITIALIZED - the appropriate connection parameters are found
  • + *
  • CONNECTING - the connection is trying to build up a connection
  • + *
  • WAITING - the connection is waiting before retrying to connect
  • + *
  • CONNECTED - the connection has just been established
  • + *
  • IDLE - the connection is connected, but waiting for work
  • + *
  • WORKING - the connection is working
  • + *
  • BROKEN - the connection has lost the connection and is waiting before reconnecting, or another unknown failure + * occurred
  • + *
  • DISCONNECTED - the connection has been disconnected
  • + *
+ * + * @author Robert von Burg + */ +public enum ConnectionState { + + // initial + CREATED, + // configured and ready to connect + INITIALIZED, + // working + CONNECTING, + WAITING, + CONNECTED, + IDLE, + WORKING, + BROKEN, + // disconnected due to connection error or manual disconnect/stop + DISCONNECTED; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionStateObserver.java b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionStateObserver.java new file mode 100644 index 000000000..156dd1056 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/ConnectionStateObserver.java @@ -0,0 +1,6 @@ +package li.strolch.communication; + +public interface ConnectionStateObserver { + + public void notify(ConnectionState oldState, String oldStateMsg, ConnectionState newState, String newStateMsg); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/IoMessage.java b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessage.java new file mode 100644 index 000000000..f9bcb9eca --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessage.java @@ -0,0 +1,215 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601FormatFactory; + +/** + *

+ * An {@link IoMessage} is the object containing the data to be transmitted in IO. Implementations of + * {@link CommunicationConnection} should implement sub classes of this method to hold the actual payload. + *

+ * + *

+ * This class also contains a {@link Map} to store transient meta data to the actual payload + *

+ * + * @author Robert von Burg + */ +public class IoMessage { + + private final String id; + private final CommandKey key; + private final String connectionId; + private Date updated; + private State state; + private String stateMsg; + private Map parameters; + + /** + * @param id + * @param key + * @param connectionId + */ + public IoMessage(String id, CommandKey key, String connectionId) { + this.id = id; + this.key = key; + this.connectionId = connectionId; + this.state = State.CREATED; + this.stateMsg = StringHelper.DASH; + this.updated = new Date(); + this.parameters = new HashMap<>(); + } + + /** + * @return the id + */ + public String getId() { + return this.id; + } + + /** + * @return the key + */ + public CommandKey getKey() { + return this.key; + } + + /** + * @return the connectionId + */ + public String getConnectionId() { + return this.connectionId; + } + + /** + * @return the updated + */ + public Date getUpdated() { + return this.updated; + } + + /** + * Used for testing purposes only! + * + * @param date + */ + void setUpdated(Date date) { + this.updated = date; + } + + /** + * @return the state + */ + public State getState() { + return this.state; + } + + /** + * @return the stateMsg + */ + public String getStateMsg() { + return this.stateMsg; + } + + /** + * @param state + * the state + * @param stateMsg + * the stateMsg + */ + public void setState(State state, String stateMsg) { + this.state = state; + this.stateMsg = stateMsg; + this.updated = new Date(); + } + + @SuppressWarnings("unchecked") + public T getParam(String key) { + return (T) this.parameters.get(key); + } + + /** + * Add a transient parameter to this message + * + * @param key + * the key under which the parameter is to be stored + * @param value + * the value to store under the given key + */ + public void addParam(String key, Object value) { + this.parameters.put(key, value); + } + + /** + * Removes the parameter with the given key + * + * @param key + * The give of the parameter to be removed + * @return the removed value, or null if the object didn't exist + */ + @SuppressWarnings("unchecked") + public T removeParam(String key) { + return (T) this.parameters.remove(key); + } + + /** + * @return the set of parameter keys + */ + public Set getParamKeys() { + return this.parameters.keySet(); + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName() + " [id="); + builder.append(this.id); + builder.append(", key="); + builder.append(this.key); + builder.append(", updated="); + builder.append(ISO8601FormatFactory.getInstance().formatDate(this.updated)); + builder.append(", state="); + builder.append(this.state); + if (StringHelper.isNotEmpty(this.stateMsg)) { + builder.append(", stateMsg="); + builder.append(this.stateMsg); + } + builder.append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.id == null) ? 0 : this.id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + IoMessage other = (IoMessage) obj; + if (this.id == null) { + if (other.id != null) + return false; + } else if (!this.id.equals(other.id)) + return false; + return true; + } + + public enum State { + CREATED, // new + PENDING, // outbound + ACCEPTED, // inbound + DONE, // completed + FAILED, // completed + FATAL; // not sendable + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageArchive.java b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageArchive.java new file mode 100644 index 000000000..8a806c0ee --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageArchive.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.util.List; + +public interface IoMessageArchive { + + public int getMaxSize(); + + public void setMaxSize(int maxSize); + + public int getTrimSize(); + + public void setTrimSize(int trimSize); + + public int size(); + + public List getAll(); + + public List getBy(String connectionId); + + public List getBy(String connectionId, CommandKey key); + + public void clearArchive(); + + public void archive(IoMessage message); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageStateObserver.java b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageStateObserver.java new file mode 100644 index 000000000..e7685d261 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageStateObserver.java @@ -0,0 +1,48 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import li.strolch.communication.IoMessage.State; + +/** + * @author Robert von Burg + */ +public class IoMessageStateObserver implements ConnectionObserver { + + private CommandKey key; + private String messageId; + private State state; + + public IoMessageStateObserver(CommandKey key, String messageId) { + this.key = key; + this.messageId = messageId; + } + + @Override + public void notify(CommandKey key, IoMessage message) { + if (this.key.equals(key) && message.getId().equals(this.messageId)) { + this.state = message.getState(); + + synchronized (this) { + notifyAll(); + } + } + } + + public State getState() { + return this.state; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageVisitor.java b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageVisitor.java new file mode 100644 index 000000000..011caca8b --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/IoMessageVisitor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.console.ConsoleMessageVisitor; + +/** + *

+ * Visitors to read and write {@link IoMessage} using different kind of endpoints. Different endpoints will require + * different ways of writing or reading message, thus this is not defined here. Known extensions are + * {@link ConsoleMessageVisitor}, {@link StreamMessageVisitor}. + *

+ * + *

+ * Concrete implementations must be thread safe! + *

+ * + * @author Robert von Burg + */ +public abstract class IoMessageVisitor { + + protected static final Logger logger = LoggerFactory.getLogger(IoMessageVisitor.class); + + protected CommunicationConnection connection; + + public void configure(CommunicationConnection connection) { + this.connection = connection; + } + + public void simulate(IoMessage ioMessage) { + // allow for subclasses to implement + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/SimpleMessageArchive.java b/li.strolch.utils/src/main/java/li/strolch/communication/SimpleMessageArchive.java new file mode 100644 index 000000000..12eae7e5e --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/SimpleMessageArchive.java @@ -0,0 +1,121 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; + +public class SimpleMessageArchive implements IoMessageArchive { + + private int maxSize; + private int trimSize; + private TreeSet messageArchive; + + public SimpleMessageArchive() { + this(1000, 100); + } + + public SimpleMessageArchive(int maxSize, int trimSize) { + this.maxSize = maxSize; + this.trimSize = trimSize; + + this.messageArchive = new TreeSet<>(new Comparator() { + @Override + public int compare(IoMessage o1, IoMessage o2) { + return o1.getUpdated().compareTo(o2.getUpdated()); + } + }); + } + + @Override + public synchronized int getMaxSize() { + return this.maxSize; + } + + @Override + public synchronized void setMaxSize(int maxSize) { + this.maxSize = maxSize; + trim(); + } + + @Override + public synchronized int getTrimSize() { + return this.trimSize; + } + + @Override + public synchronized void setTrimSize(int trimSize) { + this.trimSize = trimSize; + } + + @Override + public synchronized int size() { + return this.messageArchive.size(); + } + + @Override + public synchronized List getAll() { + List all = new ArrayList<>(this.messageArchive); + return all; + } + + @Override + public synchronized List getBy(String connectionId) { + List all = new ArrayList<>(); + for (IoMessage msg : this.messageArchive) { + if (msg.getConnectionId().equals(connectionId)) + all.add(msg); + } + return all; + } + + @Override + public synchronized List getBy(String connectionId, CommandKey key) { + List all = new ArrayList<>(); + for (IoMessage msg : this.messageArchive) { + if (msg.getConnectionId().equals(connectionId) && msg.getKey().equals(key)) + all.add(msg); + } + return all; + } + + @Override + public synchronized void clearArchive() { + this.messageArchive.clear(); + } + + @Override + public synchronized void archive(IoMessage message) { + this.messageArchive.add(message); + trim(); + } + + protected void trim() { + if (this.messageArchive.size() <= this.maxSize) + return; + + Iterator iter = this.messageArchive.iterator(); + for (int i = 0; i <= this.trimSize; i++) { + if (iter.hasNext()) { + iter.next(); + iter.remove(); + } + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/StreamMessageVisitor.java b/li.strolch.utils/src/main/java/li/strolch/communication/StreamMessageVisitor.java new file mode 100644 index 000000000..6a4fda216 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/StreamMessageVisitor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + *

+ * {@link IoMessageVisitor} to read or write using IO Streams. + *

+ * + *

+ * Concrete implementations must be thread safe! + *

+ * + * @author Robert von Burg + */ +public abstract class StreamMessageVisitor extends IoMessageVisitor { + + public abstract void visit(OutputStream outputStream, IoMessage message) throws Exception; + + public abstract IoMessage visit(InputStream inputStream) throws Exception; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/chat/Chat.java b/li.strolch.utils/src/main/java/li/strolch/communication/chat/Chat.java new file mode 100644 index 000000000..f66605be5 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/chat/Chat.java @@ -0,0 +1,133 @@ +package li.strolch.communication.chat; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.text.MessageFormat; +import java.util.Enumeration; + +import li.strolch.utils.helper.StringHelper; + +public class Chat { + + public static void main(String[] args) { + + if (args.length < 4) + printIllegalArgsAndExit(args); + + if (args[0].equals("server")) { //$NON-NLS-1$ + startServer(args); + } else if (args[0].equals("client")) { //$NON-NLS-1$ + startClient(args); + } + } + + private static void startServer(String[] args) { + + // server + InetAddress host; + String hostS = args[1]; + try { + host = InetAddress.getByName(hostS); + } catch (UnknownHostException e1) { + System.err.println(MessageFormat.format("Illegal server address: {0}", hostS)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + return; + } + boolean isHostAddress = false; + try { + for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces + .hasMoreElements();) { + NetworkInterface iface = interfaces.nextElement(); + for (Enumeration addresses = iface.getInetAddresses(); addresses.hasMoreElements();) { + InetAddress inetAddress = addresses.nextElement(); + if (inetAddress.getHostAddress().equals(host.getHostAddress())) + isHostAddress = true; + } + } + } catch (SocketException e) { + System.err.println("Oops: " + e.getMessage()); //$NON-NLS-1$ + } + + if (!isHostAddress) { + System.err.println(MessageFormat.format("The address {0} is not an address of this host!", hostS)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + } + + // port + int port; + String portS = args[2]; + try { + port = Integer.parseInt(portS); + } catch (NumberFormatException e) { + System.err.println(MessageFormat.format("Illegal port: {0}", portS)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + return; + } + if (port < 1 || port > 65535) { + System.err.println(MessageFormat.format("Illegal port: {0}", port)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + return; + } + + // username + String username = args[3]; + + // start + ChatServer chatServer = new ChatServer(host, port, username); + chatServer.start(); + } + + private static void startClient(String[] args) { + + // server + InetAddress host; + String hostS = args[1]; + try { + host = InetAddress.getByName(hostS); + } catch (UnknownHostException e1) { + System.err.println(MessageFormat.format("Illegal server address: {0}", hostS)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + return; + } + + // port + int port; + String portS = args[2]; + try { + port = Integer.parseInt(portS); + } catch (NumberFormatException e) { + System.err.println(MessageFormat.format("Illegal port: {0}", portS)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + return; + } + if (port < 1 || port > 65535) { + System.err.println(MessageFormat.format("Illegal port: {0}", port)); //$NON-NLS-1$ + printIllegalArgsAndExit(args); + return; + } + + // username + String username = args[3]; + + // start + ChatClient chatClient = new ChatClient(host, port, username); + chatClient.start(); + } + + private static void printIllegalArgsAndExit(String[] args) { + System.err.print("Illegal arguments: "); //$NON-NLS-1$ + if (args.length == 0) { + System.err.print("(none)"); //$NON-NLS-1$ + } else { + for (String arg : args) { + System.err.print(arg + StringHelper.SPACE); + } + } + System.err.println(); + System.err.println("Usage: java ...Chat server "); //$NON-NLS-1$ + System.err.println("Usage: java ...Chat client "); //$NON-NLS-1$ + System.exit(1); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatClient.java b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatClient.java new file mode 100644 index 000000000..dabf9288b --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatClient.java @@ -0,0 +1,92 @@ +package li.strolch.communication.chat; + +import static li.strolch.communication.chat.ChatMessageVisitor.inboundKey; +import static li.strolch.communication.chat.ChatMessageVisitor.outboundKey; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.ConnectionMode; +import li.strolch.communication.ConnectionObserver; +import li.strolch.communication.ConnectionState; +import li.strolch.communication.ConnectionStateObserver; +import li.strolch.communication.IoMessage; +import li.strolch.communication.tcpip.ClientSocketEndpoint; +import li.strolch.communication.tcpip.SocketEndpointConstants; +import li.strolch.communication.tcpip.SocketMessageVisitor; + +public class ChatClient implements ConnectionObserver, ConnectionStateObserver { + + private static final String id = "ChatClient"; //$NON-NLS-1$ + private InetAddress host; + private int port; + private String username; + private boolean connected; + + public ChatClient(InetAddress host, int port, String username) { + this.host = host; + this.port = port; + this.username = username; + } + + public void start() { + ConnectionMode mode = ConnectionMode.ON; + + Map parameters = new HashMap<>(); + parameters.put(SocketEndpointConstants.PARAMETER_RETRY, "10000"); //$NON-NLS-1$ + parameters.put(SocketEndpointConstants.PARAMETER_USE_TIMEOUT, Boolean.FALSE.toString()); + parameters.put(SocketEndpointConstants.PARAMETER_REMOTE_INPUT_ADDRESS, this.host.getHostAddress()); + parameters.put(SocketEndpointConstants.PARAMETER_REMOTE_INPUT_PORT, Integer.toString(this.port)); + parameters.put(SocketEndpointConstants.PARAMETER_CLOSE_AFTER_SEND, Boolean.FALSE.toString()); + + SocketMessageVisitor messageVisitor = new ChatMessageVisitor(id); + ClientSocketEndpoint endpoint = new ClientSocketEndpoint(); + + CommunicationConnection connection = new CommunicationConnection(id, mode, parameters, endpoint, messageVisitor); + connection.addConnectionObserver(outboundKey, this); + connection.addConnectionObserver(inboundKey, this); + connection.addConnectionStateObserver(this); + connection.configure(); + connection.start(); + + while (!this.connected) { + synchronized (this) { + try { + this.wait(2000l); + } catch (InterruptedException e) { + System.err.println("oops: " + e.getMessage()); //$NON-NLS-1$ + } + } + } + + System.out.println("Connected. Send messages to user:"); //$NON-NLS-1$ + while (true) { + @SuppressWarnings("resource") + Scanner in = new Scanner(System.in); + //System.out.print(this.username + ": "); + String line = in.nextLine(); + connection.send(ChatIoMessage.msg(outboundKey, id, this.username, line)); + } + } + + @Override + public void notify(CommandKey key, IoMessage message) { + if (key.equals(inboundKey)) { + ChatIoMessage chatIoMessage = (ChatIoMessage) message; + System.out.println(chatIoMessage.getChatMsg()); + } + } + + @Override + public void notify(ConnectionState oldState, String oldStateMsg, ConnectionState newState, String newStateMsg) { + this.connected = newState == ConnectionState.CONNECTED || newState == ConnectionState.IDLE + || newState == ConnectionState.WORKING; + synchronized (this) { + notifyAll(); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatIoMessage.java b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatIoMessage.java new file mode 100644 index 000000000..9806d1a4e --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatIoMessage.java @@ -0,0 +1,31 @@ +package li.strolch.communication.chat; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.IoMessage; +import li.strolch.utils.helper.StringHelper; + +public class ChatIoMessage extends IoMessage { + + private String chatMsg; + + public ChatIoMessage(String id, CommandKey key, String connectionId) { + super(id, key, connectionId); + } + + public String getChatMsg() { + return this.chatMsg; + } + + public void setChatMsg(String chagMsg) { + this.chatMsg = chagMsg; + } + + public static ChatIoMessage msg(CommandKey key, String connId, String username, String msg) { + + String line = username + StringHelper.COLON + StringHelper.SPACE + msg; + + ChatIoMessage chatIoMessage = new ChatIoMessage(StringHelper.getUniqueId(), key, connId); + chatIoMessage.setChatMsg(line); + return chatIoMessage; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatMessageVisitor.java b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatMessageVisitor.java new file mode 100644 index 000000000..13df4566b --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatMessageVisitor.java @@ -0,0 +1,45 @@ +package li.strolch.communication.chat; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStreamReader; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.IoMessage; +import li.strolch.communication.tcpip.SocketMessageVisitor; +import li.strolch.utils.helper.StringHelper; + +public class ChatMessageVisitor extends SocketMessageVisitor { + + public static final CommandKey inboundKey = CommandKey.key("server", "msg"); //$NON-NLS-1$//$NON-NLS-2$ + public static final CommandKey outboundKey = CommandKey.key("client", "msg"); //$NON-NLS-1$ //$NON-NLS-2$ + + public ChatMessageVisitor(String connectionId) { + super(connectionId); + } + + @Override + public IoMessage visit(DataInputStream inputStream, DataOutputStream outputStream) throws Exception { + + @SuppressWarnings("resource") + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + String line = bufferedReader.readLine(); + if (line == null) { + bufferedReader.close(); + return null; + } + + ChatIoMessage chatIoMessage = new ChatIoMessage(StringHelper.getUniqueId(), inboundKey, this.connectionId); + chatIoMessage.setChatMsg(line); + return chatIoMessage; + } + + @Override + public void visit(DataInputStream inputStream, DataOutputStream outputStream, IoMessage message) throws Exception { + ChatIoMessage chatIoMessage = (ChatIoMessage) message; + outputStream.writeChars(chatIoMessage.getChatMsg()); + outputStream.writeChar('\n'); + outputStream.flush(); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatServer.java b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatServer.java new file mode 100644 index 000000000..0880029f2 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/chat/ChatServer.java @@ -0,0 +1,93 @@ +package li.strolch.communication.chat; + +import static li.strolch.communication.chat.ChatMessageVisitor.inboundKey; +import static li.strolch.communication.chat.ChatMessageVisitor.outboundKey; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.ConnectionMode; +import li.strolch.communication.ConnectionObserver; +import li.strolch.communication.ConnectionState; +import li.strolch.communication.ConnectionStateObserver; +import li.strolch.communication.IoMessage; +import li.strolch.communication.tcpip.ServerSocketEndpoint; +import li.strolch.communication.tcpip.SocketEndpointConstants; +import li.strolch.communication.tcpip.SocketMessageVisitor; + +public class ChatServer implements ConnectionObserver, ConnectionStateObserver { + + private static final String id = "ChatServer"; //$NON-NLS-1$ + private InetAddress address; + private int port; + private String username; + private boolean connected; + + public ChatServer(InetAddress address, int port, String username) { + this.address = address; + this.port = port; + this.username = username; + } + + public void start() { + ConnectionMode mode = ConnectionMode.ON; + + Map parameters = new HashMap<>(); + parameters.put(SocketEndpointConstants.PARAMETER_RETRY, "10000"); //$NON-NLS-1$ + parameters.put(SocketEndpointConstants.PARAMETER_USE_TIMEOUT, Boolean.FALSE.toString()); + parameters.put(SocketEndpointConstants.PARAMETER_LOCAL_INPUT_ADDRESS, this.address.getHostAddress()); + parameters.put(SocketEndpointConstants.PARAMETER_LOCAL_INPUT_PORT, Integer.toString(this.port)); + parameters.put(SocketEndpointConstants.PARAMETER_CLOSE_AFTER_SEND, Boolean.FALSE.toString()); + parameters.put(SocketEndpointConstants.PARAMETER_CLOSE_AFTER_SEND, Boolean.FALSE.toString()); + + SocketMessageVisitor messageVisitor = new ChatMessageVisitor(id); + ServerSocketEndpoint endpoint = new ServerSocketEndpoint(); + + CommunicationConnection connection = new CommunicationConnection(id, mode, parameters, endpoint, messageVisitor); + connection.addConnectionObserver(outboundKey, this); + connection.addConnectionObserver(inboundKey, this); + connection.addConnectionStateObserver(this); + connection.configure(); + connection.start(); + + while (!this.connected) { + synchronized (this) { + try { + this.wait(2000l); + } catch (InterruptedException e) { + System.err.println("oops: " + e.getMessage()); //$NON-NLS-1$ + } + } + } + + System.out.println("Connected. Send messages to user:"); //$NON-NLS-1$ + while (true) { + @SuppressWarnings("resource") + Scanner in = new Scanner(System.in); + //System.out.print(this.username + ": "); + String line = in.nextLine(); + connection.send(ChatIoMessage.msg(outboundKey, id, this.username, line)); + } + } + + @Override + public void notify(CommandKey key, IoMessage message) { + if (key.equals(inboundKey)) { + ChatIoMessage chatIoMessage = (ChatIoMessage) message; + System.out.println(chatIoMessage.getChatMsg()); + } + } + + @Override + public void notify(ConnectionState oldState, String oldStateMsg, ConnectionState newState, String newStateMsg) { + this.connected = newState == ConnectionState.CONNECTED || newState == ConnectionState.IDLE + || newState == ConnectionState.WORKING; + synchronized (this) { + notifyAll(); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/console/ConsoleEndpoint.java b/li.strolch.utils/src/main/java/li/strolch/communication/console/ConsoleEndpoint.java new file mode 100644 index 000000000..3e6d6a513 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/console/ConsoleEndpoint.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.console; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionMessages; +import li.strolch.communication.ConnectionState; +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageVisitor; + +/** + * @author Robert von Burg + */ +public class ConsoleEndpoint implements CommunicationEndpoint { + + private static final Logger logger = LoggerFactory.getLogger(ConsoleEndpoint.class); + private CommunicationConnection connection; + private ConsoleMessageVisitor messageVisitor; + + @Override + public void configure(CommunicationConnection connection, IoMessageVisitor messageVisitor) { + this.connection = connection; + ConnectionMessages.assertLegalMessageVisitor(this.getClass(), ConsoleMessageVisitor.class, messageVisitor); + this.messageVisitor = (ConsoleMessageVisitor) messageVisitor; + } + + @Override + public void start() { + this.connection.notifyStateChange(ConnectionState.IDLE, ConnectionState.IDLE.toString()); + } + + @Override + public void stop() { + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, ConnectionState.DISCONNECTED.toString()); + } + + @Override + public void reset() { + this.connection.notifyStateChange(ConnectionState.INITIALIZED, ConnectionState.INITIALIZED.toString()); + } + + @Override + public String getLocalUri() { + return "console"; //$NON-NLS-1$ + } + + @Override + public String getRemoteUri() { + return "console"; //$NON-NLS-1$ + } + + @Override + public void send(IoMessage message) throws Exception { + this.connection.notifyStateChange(ConnectionState.WORKING, ConnectionState.WORKING.toString()); + try { + this.messageVisitor.visit(logger, message); + } finally { + this.connection.notifyStateChange(ConnectionState.IDLE, ConnectionState.IDLE.toString()); + } + } + + @Override + public void simulate(IoMessage message) throws Exception { + send(message); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/console/ConsoleMessageVisitor.java b/li.strolch.utils/src/main/java/li/strolch/communication/console/ConsoleMessageVisitor.java new file mode 100644 index 000000000..f21f0891e --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/console/ConsoleMessageVisitor.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.console; + +import org.slf4j.Logger; + +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageVisitor; + +public abstract class ConsoleMessageVisitor extends IoMessageVisitor { + + public abstract void visit(Logger logger, IoMessage message) throws Exception; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/file/FileEndpoint.java b/li.strolch.utils/src/main/java/li/strolch/communication/file/FileEndpoint.java new file mode 100644 index 000000000..68c803d23 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/file/FileEndpoint.java @@ -0,0 +1,251 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.file; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionException; +import li.strolch.communication.ConnectionMessages; +import li.strolch.communication.ConnectionState; +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageVisitor; +import li.strolch.communication.StreamMessageVisitor; +import li.strolch.utils.helper.StringHelper; + +/** + * An {@link CommunicationEndpoint} which writes and/or reads from a designated file + * + * @author Robert von Burg + */ +public class FileEndpoint implements CommunicationEndpoint, Runnable { + + public static final String ENDPOINT_MODE = "endpointMode"; //$NON-NLS-1$ + public static final String INBOUND_FILENAME = "inboundFilename"; //$NON-NLS-1$ + public static final String OUTBOUND_FILENAME = "outboundFilename"; //$NON-NLS-1$ + public static final long POLL_TIME = 1000l; + + private static final Logger logger = LoggerFactory.getLogger(FileEndpoint.class); + + private CommunicationConnection connection; + + private FileEndpointMode endpointMode; + private String inboundFilename; + private String outboundFilename; + private Thread thread; + private boolean run = false; + private StreamMessageVisitor messageVisitor; + + /** + * {@link FileEndpoint} needs the following parameters on the configuration to be initialized + *
    + *
  • outboundFilename: the file name where the {@link IoMessage} contents are written to. The value may contain + * {@link System#getProperty(String)} place holders which will be evaluated
  • + *
+ */ + @Override + public void configure(CommunicationConnection connection, IoMessageVisitor messageVisitor) { + this.connection = connection; + + ConnectionMessages.assertLegalMessageVisitor(this.getClass(), StreamMessageVisitor.class, messageVisitor); + this.messageVisitor = (StreamMessageVisitor) messageVisitor; + + configure(); + } + + private void configure() { + Map parameters = this.connection.getParameters(); + + String endpointModeS = parameters.get(ENDPOINT_MODE); + if (StringHelper.isEmpty(endpointModeS)) { + throw ConnectionMessages.throwInvalidParameter(FileEndpoint.class, ENDPOINT_MODE, endpointModeS); + } + try { + this.endpointMode = FileEndpointMode.valueOf(endpointModeS); + } catch (Exception e) { + throw ConnectionMessages.throwInvalidParameter(FileEndpoint.class, ENDPOINT_MODE, endpointModeS); + } + + if (this.endpointMode.isRead()) { + this.inboundFilename = parameters.get(INBOUND_FILENAME); + if (StringHelper.isEmpty(this.inboundFilename)) { + throw ConnectionMessages.throwInvalidParameter(FileEndpoint.class, INBOUND_FILENAME, + this.inboundFilename); + } + } + + if (this.endpointMode.isWrite()) { + this.outboundFilename = parameters.get(OUTBOUND_FILENAME); + if (StringHelper.isEmpty(this.outboundFilename)) { + throw ConnectionMessages.throwInvalidParameter(FileEndpoint.class, OUTBOUND_FILENAME, + this.outboundFilename); + } + } + } + + @Override + public String getLocalUri() { + return new File(this.inboundFilename).getAbsolutePath(); + } + + @Override + public String getRemoteUri() { + return new File(this.outboundFilename).getAbsolutePath(); + } + + @Override + public void start() { + if (this.endpointMode.isRead()) { + this.thread = new Thread(this, new File(this.inboundFilename).getName()); + this.run = true; + this.thread.start(); + } + this.connection.notifyStateChange(ConnectionState.IDLE, ConnectionState.IDLE.toString()); + } + + @Override + public void stop() { + stopThread(); + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, ConnectionState.DISCONNECTED.toString()); + } + + @Override + public void reset() { + stopThread(); + configure(); + this.connection.notifyStateChange(ConnectionState.INITIALIZED, ConnectionState.INITIALIZED.toString()); + } + + private void stopThread() { + this.run = false; + if (this.thread != null) { + try { + this.thread.interrupt(); + this.thread.join(2000l); + } catch (Exception e) { + logger.error(MessageFormat.format("Error while interrupting thread: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } + + this.thread = null; + } + } + + @Override + public void send(IoMessage message) throws Exception { + if (!this.endpointMode.isWrite()) { + String msg = "FileEnpoint mode is {0} and thus write is not allowed!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, this.endpointMode); + throw new ConnectionException(msg); + } + + this.connection.notifyStateChange(ConnectionState.WORKING, ConnectionState.WORKING.toString()); + + // open the stream + try (FileOutputStream outputStream = new FileOutputStream(this.outboundFilename, false)) { + + // write the message using the visitor + this.messageVisitor.visit(outputStream, message); + + } finally { + this.connection.notifyStateChange(ConnectionState.IDLE, ConnectionState.IDLE.toString()); + } + } + + @Override + public void simulate(IoMessage message) throws Exception { + this.messageVisitor.simulate(message); + } + + @Override + public void run() { + + File file = new File(this.inboundFilename); + + long lastModified = 0l; + + logger.info("Starting..."); //$NON-NLS-1$ + while (this.run) { + + try { + + if (file.canRead()) { + long tmpModified = file.lastModified(); + if (tmpModified > lastModified) { + + logger.info(MessageFormat.format("Handling file {0}", file.getAbsolutePath())); //$NON-NLS-1$ + + this.connection.notifyStateChange(ConnectionState.WORKING, ConnectionState.WORKING.toString()); + + // file is changed + lastModified = tmpModified; + + // read the file + handleFile(file); + + this.connection.notifyStateChange(ConnectionState.IDLE, ConnectionState.IDLE.toString()); + } + } + + if (this.run) { + this.connection.notifyStateChange(ConnectionState.WAITING, ConnectionState.WAITING.toString()); + try { + synchronized (this) { + this.wait(POLL_TIME); + } + } catch (InterruptedException e) { + this.run = false; + logger.info("Interrupted!"); //$NON-NLS-1$ + } + } + + } catch (Exception e) { + logger.error(MessageFormat.format("Error reading file: {0}", file.getAbsolutePath())); //$NON-NLS-1$ + logger.error(e.getMessage(), e); + + this.connection.notifyStateChange(ConnectionState.BROKEN, e.getLocalizedMessage()); + } + } + } + + /** + * Reads the file and handle using {@link StreamMessageVisitor} + * + * @param file + * the {@link File} to read + */ + protected void handleFile(File file) throws Exception { + + try (InputStream inputStream = new FileInputStream(file)) { + + // convert the object to an integration message + IoMessage message = this.messageVisitor.visit(inputStream); + + // and forward to the connection + if (message != null) { + this.connection.handleNewMessage(message); + } + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/file/FileEndpointMode.java b/li.strolch.utils/src/main/java/li/strolch/communication/file/FileEndpointMode.java new file mode 100644 index 000000000..bfbb2208d --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/file/FileEndpointMode.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.file; + +public enum FileEndpointMode { + READ(true, false), WRITE(false, true), READ_WRITE(true, true); + private boolean read; + private boolean write; + + private FileEndpointMode(boolean read, boolean write) { + this.read = read; + this.write = write; + } + + public boolean isRead() { + return this.read; + } + + public boolean isWrite() { + return this.write; + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/ClientSocketEndpoint.java b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/ClientSocketEndpoint.java new file mode 100644 index 000000000..7f4170344 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/ClientSocketEndpoint.java @@ -0,0 +1,538 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.tcpip; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.text.MessageFormat; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionException; +import li.strolch.communication.ConnectionMessages; +import li.strolch.communication.ConnectionState; +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageVisitor; +import li.strolch.communication.IoMessage.State; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * This {@link CommunicationEndpoint} is an abstract implementation with everything needed to connect through a + * {@link Socket} to a remote server which is listening for incoming {@link Socket} connections. This {@link Socket} + * endpoint can send messages to the remote side, as well as receive messages from the remote side + *

+ *

+ * This endpoint is maintained as a client connection. This means that this endpoint opens the {@link Socket} to the + * remote server + *

+ * + * @author Robert von Burg + */ +public class ClientSocketEndpoint implements CommunicationEndpoint { + + protected static final Logger logger = LoggerFactory.getLogger(ClientSocketEndpoint.class); + + // state variables + private boolean connected; + private boolean closed; + private long lastConnect; + private boolean useTimeout; + private int timeout; + private long retry; + private boolean clearOnConnect; + private boolean connectOnStart; + private boolean closeAfterSend; + + // remote address + private String remoteInputAddressS; + private int remoteInputPort; + private String localOutputAddressS; + private int localOutputPort; + + private InetAddress remoteInputAddress; + private InetAddress localOutputAddress; + + // connection + private Socket socket; + + protected DataOutputStream outputStream; + protected DataInputStream inputStream; + + protected CommunicationConnection connection; + + protected SocketMessageVisitor messageVisitor; + + /** + * Default constructor + */ + public ClientSocketEndpoint() { + this.connected = false; + this.closed = true; + } + + /** + * Checks the state of the connection and returns true if {@link Socket} is connected and ready for transmission, + * false otherwise + * + * @return true if {@link Socket} is connected and ready for transmission, false otherwise + */ + protected boolean checkConnection() { + return !this.closed + && this.connected + && (this.socket != null && !this.socket.isClosed() && this.socket.isBound() + && this.socket.isConnected() && !this.socket.isInputShutdown() && !this.socket + .isOutputShutdown()); + } + + /** + * Establishes a {@link Socket} connection to the remote server. This method blocks till a connection is + * established. In the event of a connection failure, the method waits a configured time before retrying + */ + protected void openConnection() { + + ConnectionState state = this.connection.getState(); + + // do not allow connecting if state is + // - CREATED + // - CONNECTING + // - WAITING + // - CLOSED + if (state == ConnectionState.CREATED || state == ConnectionState.CONNECTING || state == ConnectionState.WAITING + || state == ConnectionState.DISCONNECTED) { + + ConnectionMessages.throwIllegalConnectionState(state, ConnectionState.CONNECTING); + } + + // first close the connection + closeConnection(); + + while (!this.connected && !this.closed) { + try { + + this.connection.notifyStateChange(ConnectionState.CONNECTING, ConnectionState.CONNECTING.toString()); + + // only try in proper intervals + long currentTime = System.currentTimeMillis(); + long timeDifference = currentTime - this.lastConnect; + if (timeDifference < this.retry) { + long wait = (this.retry - timeDifference); + logger.info(MessageFormat.format("Waiting: {0}ms", wait)); //$NON-NLS-1$ + + this.connection.notifyStateChange(ConnectionState.WAITING, ConnectionState.WAITING.toString()); + Thread.sleep(wait); + this.connection + .notifyStateChange(ConnectionState.CONNECTING, ConnectionState.CONNECTING.toString()); + } + + // don't try and connect if we are closed! + if (this.closed) { + logger.error("The connection has been closed and can not be connected"); //$NON-NLS-1$ + closeConnection(); + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, null); + return; + } + + // keep track of the time of this connection attempt + this.lastConnect = System.currentTimeMillis(); + + // open the socket + if (this.localOutputAddress != null) { + String msg = "Opening connection to {0}:{1} from {2}:{3}..."; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.remoteInputAddress.getHostAddress(), + Integer.toString(this.remoteInputPort), this.localOutputAddress.getHostAddress(), + Integer.toString(this.localOutputPort))); + this.socket = new Socket(this.remoteInputAddress, this.remoteInputPort, this.localOutputAddress, + this.localOutputPort); + } else { + String msg = "Opening connection to {0}:{1}..."; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.remoteInputAddress.getHostAddress(), + Integer.toString(this.remoteInputPort))); + this.socket = new Socket(this.remoteInputAddress, this.remoteInputPort); + } + + // configure the socket + if (logger.isDebugEnabled()) { + String msg = "BufferSize (send/read): {0} / {1} SoLinger: {2} TcpNoDelay: {3}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.socket.getSendBufferSize(), + this.socket.getReceiveBufferSize(), this.socket.getSoLinger(), this.socket.getTcpNoDelay())); + } + //outputSocket.setSendBufferSize(1); + //outputSocket.setSoLinger(true, 0); + //outputSocket.setTcpNoDelay(true); + + // activate connection timeout + if (this.useTimeout) { + this.socket.setSoTimeout(this.timeout); + } + + // get the streams + this.outputStream = new DataOutputStream(this.socket.getOutputStream()); + this.inputStream = new DataInputStream(this.socket.getInputStream()); + + if (this.clearOnConnect) { + // clear the input stream + int available = this.inputStream.available(); + logger.info(MessageFormat.format("clearOnConnect: skipping {0} bytes.", available)); //$NON-NLS-1$ + this.inputStream.skip(available); + } + + String msg = "Connected {0}: {1}:{2} with local side {3}:{4}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.connection.getId(), this.remoteInputAddressS, + Integer.toString(this.remoteInputPort), this.socket.getLocalAddress().getHostAddress(), + Integer.toString(this.socket.getLocalPort()))); + + // we are connected! + this.connection.notifyStateChange(ConnectionState.CONNECTED, ConnectionState.CONNECTED.toString()); + this.connected = true; + + } catch (InterruptedException e) { + logger.info("Interrupted!"); //$NON-NLS-1$ + this.closed = true; + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, null); + } catch (Exception e) { + String msg = "Error while connecting to {0}:{1}: {2}"; //$NON-NLS-1$ + logger.error( + MessageFormat.format(msg, this.remoteInputAddressS, Integer.toString(this.remoteInputPort)), + e.getMessage()); + this.connection.notifyStateChange(ConnectionState.BROKEN, e.getLocalizedMessage()); + } + } + } + + /** + * closes the connection HARD by calling close() on the streams and socket. All Exceptions are caught to make sure + * that the connections are cleaned up + */ + protected void closeConnection() { + + this.connected = false; + this.connection.notifyStateChange(ConnectionState.BROKEN, null); + + if (this.outputStream != null) { + try { + this.outputStream.close(); + } catch (IOException e) { + logger.error(MessageFormat.format("Error closing OutputStream: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } finally { + this.outputStream = null; + } + } + + if (this.inputStream != null) { + try { + this.inputStream.close(); + } catch (IOException e) { + logger.error(MessageFormat.format("Error closing InputStream: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } finally { + this.inputStream = null; + } + } + + if (this.socket != null) { + try { + this.socket.close(); + } catch (IOException e) { + logger.error(MessageFormat.format("Error closing OutputSocket: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } finally { + this.socket = null; + } + + String msg = "Socket closed for connection {0} at remote input address {1}:{2}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.connection.getId(), this.remoteInputAddressS, + Integer.toString(this.remoteInputPort))); + } + } + + /** + *

+ * Configures this {@link ClientSocketEndpoint} + *

+ * gets the parameter map from the connection and reads the following parameters from the map: + *
    + *
  • remoteInputAddress - the IP or Hostname of the remote server
  • + *
  • remoteInputPort - the port to which the socket should be established
  • + *
  • localOutputAddress - the IP or Hostname of the local server (if null, then the network layer will decide)
  • + *
  • localOutputPort - the local port from which the socket should go out of (if null, then the network layer will + * decide)
  • + *
  • retry - a configured retry wait time. Default is {@link SocketEndpointConstants#RETRY}
  • + *
  • timeout - the timeout after which an idle socket is deemed dead. Default is + * {@link SocketEndpointConstants#TIMEOUT}
  • + *
  • useTimeout - if true, then the timeout is activated, otherwise it is. default is + * {@link SocketEndpointConstants#USE_TIMEOUT}
  • + *
  • clearOnConnect - if true, then the after a successful connect the input is cleared by discarding all + * available bytes. This can be useful in cases where the channel is clogged with stale data. default is + * {@link SocketEndpointConstants#CLEAR_ON_CONNECT}
  • + *
  • connectOnStart - if true, then when the connection is started, the connection to the remote address is + * attempted. default is {@link SocketEndpointConstants#CONNECT_ON_START} + *
+ * + * @see CommunicationEndpoint#configure(CommunicationConnection, IoMessageVisitor) + */ + @Override + public void configure(CommunicationConnection connection, IoMessageVisitor messageVisitor) { + if (this.connection != null && connection.getState().compareTo(ConnectionState.INITIALIZED) > 0) { + String msg = "{0}:{1} already configured."; //$NON-NLS-1$ + logger.warn(MessageFormat.format(msg, this.getClass().getSimpleName(), connection.getId())); + return; + } + + ConnectionMessages.assertLegalMessageVisitor(this.getClass(), SocketMessageVisitor.class, messageVisitor); + this.messageVisitor = (SocketMessageVisitor) messageVisitor; + this.connection = connection; + configure(); + } + + private void configure() { + Map parameters = this.connection.getParameters(); + + this.remoteInputAddressS = parameters.get(SocketEndpointConstants.PARAMETER_REMOTE_INPUT_ADDRESS); + String remoteInputPortS = parameters.get(SocketEndpointConstants.PARAMETER_REMOTE_INPUT_PORT); + this.localOutputAddressS = parameters.get(SocketEndpointConstants.PARAMETER_LOCAL_OUTPUT_ADDRESS); + String localOutputPortS = parameters.get(SocketEndpointConstants.PARAMETER_LOCAL_OUTPUT_PORT); + + // parse remote input Address to InetAddress object + try { + this.remoteInputAddress = InetAddress.getByName(this.remoteInputAddressS); + } catch (UnknownHostException e) { + throw ConnectionMessages.throwInvalidParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_REMOTE_INPUT_ADDRESS, this.remoteInputAddressS); + } + + // parse remote input address port to integer + try { + this.remoteInputPort = Integer.parseInt(remoteInputPortS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_REMOTE_INPUT_PORT, remoteInputPortS); + } + + // if local output address is not set, then we will use the localhost InetAddress + if (this.localOutputAddressS == null || this.localOutputAddressS.length() == 0) { + logger.debug("No localOutputAddress set. Using localhost"); //$NON-NLS-1$ + } else { + + // parse local output address name to InetAddress object + try { + this.localOutputAddress = InetAddress.getByName(this.localOutputAddressS); + } catch (UnknownHostException e) { + String msg = "The host name ''{0}'' can not be evaluated to an internet address"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, this.localOutputAddressS); + throw new ConnectionException(msg, e); + } + + // parse local output address port to integer + try { + this.localOutputPort = Integer.parseInt(localOutputPortS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_LOCAL_OUTPUT_PORT, localOutputPortS); + } + } + + // configure retry wait time + String retryS = parameters.get(SocketEndpointConstants.PARAMETER_RETRY); + if (retryS == null || retryS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ClientSocketEndpoint.class, SocketEndpointConstants.PARAMETER_RETRY, + String.valueOf(SocketEndpointConstants.RETRY)); + this.retry = SocketEndpointConstants.RETRY; + } else { + try { + this.retry = Long.parseLong(retryS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_RETRY, retryS); + } + } + + // configure connect on start + String connectOnStartS = parameters.get(SocketEndpointConstants.PARAMETER_CONNECT_ON_START); + if (StringHelper.isNotEmpty(connectOnStartS)) { + this.connectOnStart = StringHelper.parseBoolean(connectOnStartS); + } else { + ConnectionMessages.warnUnsetParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_CONNECT_ON_START, + String.valueOf(SocketEndpointConstants.CONNECT_ON_START)); + this.connectOnStart = SocketEndpointConstants.CONNECT_ON_START; + } + + // configure closeAfterSend + String closeAfterSendS = parameters.get(SocketEndpointConstants.PARAMETER_CLOSE_AFTER_SEND); + if (StringHelper.isNotEmpty(closeAfterSendS)) { + this.closeAfterSend = StringHelper.parseBoolean(closeAfterSendS); + } else { + ConnectionMessages.warnUnsetParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_CLOSE_AFTER_SEND, + String.valueOf(SocketEndpointConstants.CLOSE_AFTER_SEND)); + this.closeAfterSend = SocketEndpointConstants.CLOSE_AFTER_SEND; + } + + // configure if timeout on connection should be activated + String useTimeoutS = parameters.get(SocketEndpointConstants.PARAMETER_USE_TIMEOUT); + if (useTimeoutS == null || useTimeoutS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_USE_TIMEOUT, String.valueOf(SocketEndpointConstants.USE_TIMEOUT)); + this.useTimeout = SocketEndpointConstants.USE_TIMEOUT; + } else { + this.useTimeout = Boolean.parseBoolean(useTimeoutS); + } + + if (this.useTimeout) { + // configure timeout on connection + String timeoutS = parameters.get(SocketEndpointConstants.PARAMETER_TIMEOUT); + if (timeoutS == null || timeoutS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_TIMEOUT, String.valueOf(SocketEndpointConstants.TIMEOUT)); + this.timeout = SocketEndpointConstants.TIMEOUT; + } else { + try { + this.timeout = Integer.parseInt(timeoutS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_TIMEOUT, timeoutS); + } + } + } + + // configure if the connection should be cleared on connect + String clearOnConnectS = parameters.get(SocketEndpointConstants.PARAMETER_CLEAR_ON_CONNECT); + if (clearOnConnectS == null || clearOnConnectS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ClientSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_CLEAR_ON_CONNECT, + String.valueOf(SocketEndpointConstants.CLEAR_ON_CONNECT)); + this.clearOnConnect = SocketEndpointConstants.CLEAR_ON_CONNECT; + } else { + this.clearOnConnect = Boolean.parseBoolean(clearOnConnectS); + } + } + + /** + * @return the uri as String to which this {@link ClientSocketEndpoint} is locally bound to + */ + @Override + public String getLocalUri() { + if (this.socket != null) { + InetAddress localAddress = this.socket.getLocalAddress(); + return localAddress.getHostAddress() + StringHelper.COLON + this.socket.getLocalPort(); + } else if (this.localOutputAddress != null) { + return this.localOutputAddress.getHostAddress() + StringHelper.COLON + this.localOutputPort; + } + + return "0.0.0.0:0"; //$NON-NLS-1$ + } + + /** + * @return the uri as String to which this {@link ClientSocketEndpoint} is connecting to + */ + @Override + public String getRemoteUri() { + if (this.socket != null) { + InetAddress remoteAddress = this.socket.getInetAddress(); + return remoteAddress.getHostAddress() + StringHelper.COLON + this.socket.getPort(); + } else if (this.remoteInputAddress != null) { + return this.remoteInputAddress.getHostAddress() + StringHelper.COLON + this.remoteInputPort; + } + + return this.remoteInputAddressS + StringHelper.COLON + this.remoteInputPort; + } + + /** + * Allows this end point to connect and then opens the connection to the defined remote server + * + * @see CommunicationEndpoint#start() + */ + @Override + public void start() { + if (!this.closed) { + logger.warn(MessageFormat.format("CommunicationConnection {0} already started.", this.connection.getId())); //$NON-NLS-1$ + } else { + // logger.info(MessageFormat.format("Enabling connection {0}...", this.connection.getId())); //$NON-NLS-1$ + this.closed = false; + this.connection.notifyStateChange(ConnectionState.INITIALIZED, ConnectionState.INITIALIZED.toString()); + if (this.connectOnStart) { + openConnection(); + } + } + } + + /** + * Closes this connection and disallows this end point to reconnect + * + * @see CommunicationEndpoint#stop() + */ + @Override + public void stop() { + this.closed = true; + + closeConnection(); + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, ConnectionState.DISCONNECTED.toString()); + + logger.info(MessageFormat.format("Disabled connection {0}.", this.connection.getId())); //$NON-NLS-1$ + } + + @Override + public void reset() { + this.closed = true; + closeConnection(); + this.connection.notifyStateChange(ConnectionState.INITIALIZED, ConnectionState.INITIALIZED.toString()); + } + + @Override + public void simulate(IoMessage message) throws Exception { + this.messageVisitor.simulate(message); + } + + @Override + public void send(IoMessage message) throws Exception { + + while (!this.closed && message.getState() == State.PENDING) { + try { + + // open the connection + if (!checkConnection()) + openConnection(); + + // read and write to the client socket + this.messageVisitor.visit(this.inputStream, this.outputStream, message); + + message.setState(State.DONE, State.DONE.name()); + + } catch (Exception e) { + if (this.closed) { + logger.warn("Socket has been closed!"); //$NON-NLS-1$ + message.setState(State.FATAL, "Socket has been closed!"); //$NON-NLS-1$ + } else { + closeConnection(); + logger.error(e.getMessage(), e); + message.setState(State.FATAL, e.getLocalizedMessage()); + this.connection.notifyStateChange(ConnectionState.BROKEN, e.getLocalizedMessage()); + } + } finally { + if (this.closeAfterSend && !this.closed) { + closeConnection(); + } + } + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/ServerSocketEndpoint.java b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/ServerSocketEndpoint.java new file mode 100644 index 000000000..191ce30ec --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/ServerSocketEndpoint.java @@ -0,0 +1,594 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.tcpip; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.text.MessageFormat; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionException; +import li.strolch.communication.ConnectionMessages; +import li.strolch.communication.ConnectionState; +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageVisitor; +import li.strolch.utils.helper.StringHelper; + +/** + *

+ * This {@link CommunicationEndpoint} is an abstract implementation with everything needed to start a {@link Socket} + * server which waits for a request from a single client + *

+ *

+ * This end point only allows a single connection at a time and implements all exception handling for opening and + * closing a {@link Socket} connection + *

+ * + * @see ServerSocketEndpoint#configure(CommunicationConnection, IoMessageVisitor) for details on configuring the end + * point + * + * @author Robert von Burg + */ +public class ServerSocketEndpoint implements CommunicationEndpoint, Runnable { + + protected static final Logger logger = LoggerFactory.getLogger(ServerSocketEndpoint.class); + + private Thread serverThread; + + // state variables + private boolean connected; + private boolean closed; + private boolean fatal; + private long lastConnect; + private boolean useTimeout; + private int timeout; + private long retry; + private boolean clearOnConnect; + + // address + private String localInputAddressS; + private int localInputPort; + private String remoteOutputAddressS; + private int remoteOutputPort; + + private InetAddress localInputAddress; + private InetAddress remoteOutputAddress; + + // connection + private ServerSocket serverSocket; + private Socket socket; + + protected DataOutputStream outputStream; + protected DataInputStream inputStream; + + protected CommunicationConnection connection; + + protected SocketMessageVisitor messageVisitor; + + /** + * Default constructor + */ + public ServerSocketEndpoint() { + this.connected = false; + this.closed = true; + this.fatal = false; + } + + /** + * Checks the state of the connection and returns true if {@link Socket} is connected and ready for transmission, + * false otherwise + * + * @return true if {@link Socket} is connected and ready for transmission, false otherwise + */ + protected boolean checkConnection() { + return !this.closed + && this.connected + && (this.socket != null && !this.socket.isClosed() && this.socket.isBound() + && this.socket.isConnected() && !this.socket.isInputShutdown() && !this.socket + .isOutputShutdown()); + } + + /** + * Listens on the {@link ServerSocket} for an incoming connection. Prepares the connection then for use. If the + * remote address has been defined, then the remote connection is validated to come from this appropriate host. + * CommunicationConnection attempts are always separated by a configured amount of time + */ + protected void openConnection() { + + ConnectionState state = this.connection.getState(); + + // do not open the connection if state is + // - CREATED + // - CONNECTING + // - WAITING + // - CLOSED + if (state == ConnectionState.CREATED || state == ConnectionState.CONNECTING || state == ConnectionState.WAITING + || state == ConnectionState.DISCONNECTED) { + + ConnectionMessages.throwIllegalConnectionState(state, ConnectionState.CONNECTING); + } + + // first close the connection + closeConnection(); + + while (!this.connected && !this.closed) { + try { + + this.connection.notifyStateChange(ConnectionState.CONNECTING, ConnectionState.CONNECTING.toString()); + + // only try in proper intervals + long currentTime = System.currentTimeMillis(); + long timeDifference = currentTime - this.lastConnect; + if (timeDifference < this.retry) { + long wait = this.retry - timeDifference; + logger.info(MessageFormat.format("Waiting: {0}ms", wait)); //$NON-NLS-1$ + + this.connection.notifyStateChange(ConnectionState.WAITING, ConnectionState.WAITING.toString()); + Thread.sleep(wait); + this.connection + .notifyStateChange(ConnectionState.CONNECTING, ConnectionState.CONNECTING.toString()); + } + + // don't try and connect if we are closed! + if (this.closed) { + logger.error("The connection has been closed and can not be connected"); //$NON-NLS-1$ + closeConnection(); + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, null); + return; + } + + // keep track of the time of this connection attempt + this.lastConnect = System.currentTimeMillis(); + + // open the socket + String msg = "Waiting for connections on: {0}:{1}..."; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.localInputAddress.getHostAddress(), + Integer.toString(this.localInputPort))); + this.socket = this.serverSocket.accept(); + + // validate that the remote side of the socket is really the client we want + if (this.remoteOutputAddress != null) { + + String remoteAddr = this.socket.getInetAddress().getHostAddress(); + if (!remoteAddr.equals(this.remoteOutputAddress.getHostAddress())) { + msg = "Illegal remote client at address {0}. Expected is {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, remoteAddr, this.remoteOutputAddress.getHostAddress()); + logger.error(msg); + + closeConnection(); + + throw new ConnectionException(msg); + } + } + + // configure the socket + if (logger.isDebugEnabled()) { + msg = "BufferSize (send/read): {0} / {1} SoLinger: {2} TcpNoDelay: {3}"; //$NON-NLS-1$ + logger.debug(MessageFormat.format(msg, this.socket.getSendBufferSize(), + this.socket.getReceiveBufferSize(), this.socket.getSoLinger(), this.socket.getTcpNoDelay())); + } + //inputSocket.setSendBufferSize(1); + //inputSocket.setSoLinger(true, 0); + //inputSocket.setTcpNoDelay(true); + + // activate connection timeout + if (this.useTimeout) { + this.socket.setSoTimeout(this.timeout); + } + + // get the streams + this.outputStream = new DataOutputStream(this.socket.getOutputStream()); + this.inputStream = new DataInputStream(this.socket.getInputStream()); + + if (this.clearOnConnect) { + // clear the input stream + int available = this.inputStream.available(); + logger.info(MessageFormat.format("clearOnConnect: skipping {0} bytes.", available)); //$NON-NLS-1$ + this.inputStream.skip(available); + } + + msg = "Connected {0}{1}: {2}:{3} with local side {4}:{5}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.getClass().getSimpleName(), this.connection.getId(), + this.socket.getInetAddress().getHostName(), Integer.toString(this.socket.getPort()), + this.socket.getLocalAddress().getHostAddress(), Integer.toString(this.socket.getLocalPort()))); + + // we are connected! + this.connection.notifyStateChange(ConnectionState.CONNECTED, ConnectionState.CONNECTED.toString()); + this.connected = true; + + } catch (InterruptedException e) { + logger.warn("Interrupted!"); //$NON-NLS-1$ + this.closed = true; + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, null); + } catch (Exception e) { + if (this.closed && e instanceof SocketException) { + logger.warn("Socket closed!"); //$NON-NLS-1$ + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, null); + } else { + String msg = "Error while opening socket for inbound connection {0}: {1}"; //$NON-NLS-1$ + logger.error(MessageFormat.format(msg, this.connection.getId()), e.getMessage()); + this.connected = false; + this.connection.notifyStateChange(ConnectionState.BROKEN, e.getLocalizedMessage()); + } + } + } + } + + /** + * closes the connection HARD by calling close() on the streams and socket. All Exceptions are caught to make sure + * that the connections are cleaned up + */ + protected void closeConnection() { + + this.connected = false; + this.connection.notifyStateChange(ConnectionState.BROKEN, null); + + if (this.outputStream != null) { + try { + this.outputStream.close(); + } catch (IOException e) { + logger.error(MessageFormat.format("Error closing OutputStream: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } finally { + this.outputStream = null; + } + } + + if (this.inputStream != null) { + try { + this.inputStream.close(); + } catch (IOException e) { + logger.error(MessageFormat.format("Error closing InputStream: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } finally { + this.inputStream = null; + } + } + + if (this.socket != null) { + try { + this.socket.close(); + } catch (IOException e) { + logger.error(MessageFormat.format("Error closing InputSocket: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } finally { + this.socket = null; + } + + String msg = "Socket closed for inbound connection {0} at local input address {1}:{2}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.connection.getId(), this.localInputAddressS, + Integer.toString(this.localInputPort))); + } + } + + /** + *

+ * Configures this {@link ServerSocketEndpoint} + *

+ * gets the parameter map from the connection and reads the following parameters from the map: + *
    + *
  • localInputAddress - the local IP or Hostname to bind to for incoming connections
  • + *
  • localInputPort - the local port on which to listen for incoming connections
  • + *
  • remoteOutputAddress - the IP or Hostname of the remote client. If this value is not null, then it will be + * verified that the connecting client is connecting from this address
  • + *
  • remoteOutputPort - the port from which the remote client must connect. If this value is not null, then it + * will be verified that the connecting client is connecting from this port
  • + *
  • retry - a configured retry wait time. Default is {@link SocketEndpointConstants#RETRY}
  • + *
  • timeout - the timeout after which an idle socket is deemed dead. Default is + * {@link SocketEndpointConstants#TIMEOUT}
  • + *
  • useTimeout - if true, then the timeout is activated. default is {@link SocketEndpointConstants#USE_TIMEOUT}
  • + *
  • clearOnConnect - if true, then the after a successful connect the input is cleared by discarding all + * available bytes. This can be useful in cases where the channel is clogged with stale data. default is + * {@link SocketEndpointConstants#CLEAR_ON_CONNECT}
  • + *
+ * + * @see CommunicationEndpoint#configure(CommunicationConnection, IoMessageVisitor) + */ + @Override + public void configure(CommunicationConnection connection, IoMessageVisitor messageVisitor) { + if (this.connection != null && connection.getState().compareTo(ConnectionState.INITIALIZED) > 0) { + logger.warn(MessageFormat.format("Inbound connection {0} already configured.", connection.getId())); //$NON-NLS-1$ + return; + } + + ConnectionMessages.assertLegalMessageVisitor(this.getClass(), SocketMessageVisitor.class, messageVisitor); + this.messageVisitor = (SocketMessageVisitor) messageVisitor; + this.connection = connection; + configure(); + } + + private void configure() { + Map parameters = this.connection.getParameters(); + + this.localInputAddressS = parameters.get(SocketEndpointConstants.PARAMETER_LOCAL_INPUT_ADDRESS); + String localInputPortS = parameters.get(SocketEndpointConstants.PARAMETER_LOCAL_INPUT_PORT); + this.remoteOutputAddressS = parameters.get(SocketEndpointConstants.PARAMETER_REMOTE_OUTPUT_ADDRESS); + String remoteOutputPortS = parameters.get(SocketEndpointConstants.PARAMETER_REMOTE_OUTPUT_PORT); + + // parse local Address to InetAddress object + try { + this.localInputAddress = InetAddress.getByName(this.localInputAddressS); + } catch (UnknownHostException e) { + throw ConnectionMessages.throwInvalidParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_LOCAL_INPUT_ADDRESS, this.localInputAddressS); + } + + // parse local address port to integer + try { + this.localInputPort = Integer.parseInt(localInputPortS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_LOCAL_INPUT_PORT, localInputPortS); + } + + // if remote address is not set, then we will use the localhost InetAddress + if (this.remoteOutputAddressS == null || this.remoteOutputAddressS.length() == 0) { + logger.debug("No remoteOutputAddress set. Allowing connection from any remote address"); //$NON-NLS-1$ + } else { + + // parse remote output address name to InetAddress object + try { + this.remoteOutputAddress = InetAddress.getByName(this.remoteOutputAddressS); + } catch (UnknownHostException e) { + throw ConnectionMessages.throwInvalidParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_REMOTE_OUTPUT_ADDRESS, this.remoteOutputAddressS); + } + + // parse remote output address port to integer + try { + this.remoteOutputPort = Integer.parseInt(remoteOutputPortS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_REMOTE_OUTPUT_PORT, remoteOutputPortS); + } + } + + // configure retry wait time + String retryS = parameters.get(SocketEndpointConstants.PARAMETER_RETRY); + if (retryS == null || retryS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ServerSocketEndpoint.class, SocketEndpointConstants.PARAMETER_RETRY, + String.valueOf(SocketEndpointConstants.RETRY)); + this.retry = SocketEndpointConstants.RETRY; + } else { + try { + this.retry = Long.parseLong(retryS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_RETRY, retryS); + } + } + + // configure if timeout on connection should be activated + String useTimeoutS = parameters.get(SocketEndpointConstants.PARAMETER_USE_TIMEOUT); + if (useTimeoutS == null || useTimeoutS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_USE_TIMEOUT, String.valueOf(SocketEndpointConstants.USE_TIMEOUT)); + this.useTimeout = SocketEndpointConstants.USE_TIMEOUT; + } else { + this.useTimeout = Boolean.parseBoolean(useTimeoutS); + } + + if (this.useTimeout) { + // configure timeout on connection + String timeoutS = parameters.get(SocketEndpointConstants.PARAMETER_TIMEOUT); + if (timeoutS == null || timeoutS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_TIMEOUT, String.valueOf(SocketEndpointConstants.TIMEOUT)); + this.timeout = SocketEndpointConstants.TIMEOUT; + } else { + try { + this.timeout = Integer.parseInt(timeoutS); + } catch (NumberFormatException e) { + throw ConnectionMessages.throwInvalidParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_TIMEOUT, timeoutS); + } + } + } + + // configure if the connection should be cleared on connect + String clearOnConnectS = parameters.get(SocketEndpointConstants.PARAMETER_CLEAR_ON_CONNECT); + if (clearOnConnectS == null || clearOnConnectS.length() == 0) { + ConnectionMessages.warnUnsetParameter(ServerSocketEndpoint.class, + SocketEndpointConstants.PARAMETER_CLEAR_ON_CONNECT, + String.valueOf(SocketEndpointConstants.CLEAR_ON_CONNECT)); + this.clearOnConnect = SocketEndpointConstants.CLEAR_ON_CONNECT; + } else { + this.clearOnConnect = Boolean.parseBoolean(clearOnConnectS); + } + } + + /** + * @return the uri as String to which this {@link ServerSocketEndpoint} is locally bound to + */ + @Override + public String getLocalUri() { + if (this.socket != null) { + InetAddress localAddress = this.socket.getLocalAddress(); + return localAddress.getHostAddress() + StringHelper.COLON + this.socket.getLocalPort(); + } else if (this.localInputAddress != null) { + return this.localInputAddress.getHostAddress() + StringHelper.COLON + this.localInputPort; + } + + return "0.0.0.0:0"; //$NON-NLS-1$ + } + + /** + * @return the uri as String from which this {@link ServerSocketEndpoint} is receiving data from + */ + @Override + public String getRemoteUri() { + if (this.socket != null) { + InetAddress remoteAddress = this.socket.getInetAddress(); + return remoteAddress.getHostAddress() + StringHelper.COLON + this.socket.getPort(); + } else if (this.remoteOutputAddressS != null) { + return this.remoteOutputAddress.getHostAddress() + StringHelper.COLON + this.remoteOutputPort; + } + + return "0.0.0.0:0"; //$NON-NLS-1$ + } + + /** + * Starts the {@link Thread} to allow incoming connections + * + * @see CommunicationEndpoint#start() + */ + @Override + public void start() { + + if (this.fatal) { + String msg = "CommunicationConnection had a fatal exception and can not yet be started. Please check log file for further information!"; //$NON-NLS-1$ + throw new ConnectionException(msg); + } + + if (this.serverThread != null) { + logger.warn(MessageFormat.format("CommunicationConnection {0} already started.", this.connection.getId())); //$NON-NLS-1$ + } else { + // logger.info(MessageFormat.format("Enabling connection {0}...", this.connection.getId())); //$NON-NLS-1$ + this.closed = false; + + this.serverThread = new Thread(this, this.connection.getId()); + this.serverThread.start(); + } + } + + /** + * Closes any open connection and then stops the {@link Thread} disallowing incoming connections + * + * @see CommunicationEndpoint#stop() + */ + @Override + public void stop() { + closeThread(); + closeConnection(); + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, ConnectionState.DISCONNECTED.toString()); + + logger.info(MessageFormat.format("Disabled connection {0}.", this.connection.getId())); //$NON-NLS-1$ + } + + @Override + public void reset() { + closeThread(); + closeConnection(); + configure(); + this.connection.notifyStateChange(ConnectionState.INITIALIZED, ConnectionState.INITIALIZED.toString()); + } + + private void closeThread() { + this.closed = true; + this.fatal = false; + + if (this.serverThread != null) { + try { + this.serverThread.interrupt(); + if (this.serverSocket != null) + this.serverSocket.close(); + this.serverThread.join(2000l); + } catch (Exception e) { + logger.error(MessageFormat.format( + "Exception while interrupting server thread: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + } + + this.serverThread = null; + } + } + + /** + * Thread is listening on the ServerSocket and opens a new connection if necessary + */ + @Override + public void run() { + + while (!this.closed) { + + // bomb-proof, catches all exceptions! + try { + + // if serverSocket is null or closed, open a new server socket + if (this.serverSocket == null || this.serverSocket.isClosed()) { + + try { + // String msg = "Opening socket on {0}:{1}..."; //$NON-NLS-1$ + // logger.info(MessageFormat.format(msg, this.localInputAddress.getHostAddress(), + // Integer.toString(this.localInputPort))); + this.serverSocket = new ServerSocket(this.localInputPort, 1, this.localInputAddress); + this.serverSocket.setReuseAddress(true); + } catch (BindException e) { + logger.error("Fatal BindException occurred! Port is already in use, or address is illegal!"); //$NON-NLS-1$ + logger.error(e.getMessage(), e); + this.closed = true; + this.fatal = true; + + String msg = "Fatal error while binding to server socket. ServerSocket endpoint is dead"; //$NON-NLS-1$ + throw new ConnectionException(msg); + } + } + + // open the connection + openConnection(); + + // as long as connection is connected + while (checkConnection()) { + + // read and write from the connected server socket + IoMessage message = this.messageVisitor.visit(this.inputStream, this.outputStream); + if (message != null) { + this.connection.handleNewMessage(message); + } + } + + } catch (Exception e) { + if (e instanceof InterruptedException) { + logger.error("Interrupted!"); //$NON-NLS-1$ + } else { + logger.error(e.getMessage(), e); + } + this.connection.notifyStateChange(ConnectionState.BROKEN, e.getLocalizedMessage()); + } finally { + closeConnection(); + } + } + + if (!this.fatal) { + logger.warn(MessageFormat.format( + "CommunicationConnection {0} is not running anymore!", this.connection.getId())); //$NON-NLS-1$ + this.connection.notifyStateChange(ConnectionState.BROKEN, null); + } else { + String msg = "CommunicationConnection {0} is broken due to a fatal exception!"; //$NON-NLS-1$ + logger.error(MessageFormat.format(msg, this.connection.getId())); + this.connection.notifyStateChange(ConnectionState.DISCONNECTED, null); + } + } + + @Override + public void simulate(IoMessage message) throws Exception { + send(message); + } + + @Override + public void send(IoMessage message) throws Exception { + String msg = "The Server Socket can not send messages, use the {0} implementation instead!"; //$NON-NLS-1$ + throw new UnsupportedOperationException(MessageFormat.format(msg, ClientSocketEndpoint.class.getName())); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/SocketEndpointConstants.java b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/SocketEndpointConstants.java new file mode 100644 index 000000000..b9a98daa8 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/SocketEndpointConstants.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.tcpip; + +/** + * Constants used in the communication classes + * + * @author Robert von Burg + */ +public class SocketEndpointConstants { + + public static final String PARAMETER_USE_TIMEOUT = "useTimeout"; //$NON-NLS-1$ + public static final String PARAMETER_TIMEOUT = "timeout"; //$NON-NLS-1$ + public static final String PARAMETER_RETRY = "retry"; //$NON-NLS-1$ + public static final String PARAMETER_CLEAR_ON_CONNECT = "clearOnConnect"; //$NON-NLS-1$ + public static final String PARAMETER_CONNECT_ON_START = "connectOnStart"; //$NON-NLS-1$ + public static final String PARAMETER_CLOSE_AFTER_SEND = "closeAfterSend"; //$NON-NLS-1$ + + public static final String PARAMETER_REMOTE_OUTPUT_PORT = "remoteOutputPort"; //$NON-NLS-1$ + public static final String PARAMETER_REMOTE_OUTPUT_ADDRESS = "remoteOutputAddress"; //$NON-NLS-1$ + public static final String PARAMETER_LOCAL_INPUT_PORT = "localInputPort"; //$NON-NLS-1$ + public static final String PARAMETER_LOCAL_INPUT_ADDRESS = "localInputAddress"; //$NON-NLS-1$ + + public static final String PARAMETER_LOCAL_OUTPUT_ADDRESS = "localOutputAddress"; //$NON-NLS-1$ + public static final String PARAMETER_LOCAL_OUTPUT_PORT = "localOutputPort"; //$NON-NLS-1$ + public static final String PARAMETER_REMOTE_INPUT_ADDRESS = "remoteInputAddress"; //$NON-NLS-1$ + public static final String PARAMETER_REMOTE_INPUT_PORT = "remoteInputPort"; //$NON-NLS-1$ + + /** + * Time to wait in milliseconds before reestablishing a connection. Default is 60000ms + */ + public static final long RETRY = 60000l; + + /** + * The time after which a connection is deemed dead. Value is 60000ms + */ + public static final int TIMEOUT = 60000; + + /** + * Default is to use a timeout on socket connections, thus this value is true + */ + public static final boolean USE_TIMEOUT = true; + + /** + * Default is to not clear the input socket on connect, thus this value is false + */ + public static final boolean CLEAR_ON_CONNECT = false; + + /** + * Default is to connect on start of the connection + */ + public static final boolean CONNECT_ON_START = true; + + /** + * Default is to not close after sending + */ + public static final boolean CLOSE_AFTER_SEND = false; + + /** + * Default is to disconnect after a null message is received when reading from a TCP socket, thus this value is true + */ + public static final boolean DISCONNECT_ON_NULL_MSG = true; + + /** + * If {@link #DISCONNECT_ON_NULL_MSG} is activated, then this is the default time used to wait before reading again, + * which is 10000ms + */ + public static final long WAIT_TIME_ON_NULL_MSG = 10000l; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/SocketMessageVisitor.java b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/SocketMessageVisitor.java new file mode 100644 index 000000000..f7c35e225 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/communication/tcpip/SocketMessageVisitor.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication.tcpip; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.net.Socket; + +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageVisitor; + +/** + * This {@link IoMessageVisitor} implements and endpoint connecting to a {@link Socket}. + * + * @author Robert von Burg + */ +public abstract class SocketMessageVisitor extends IoMessageVisitor { + + protected final String connectionId; + + public SocketMessageVisitor(String connectionId) { + this.connectionId = connectionId; + } + + public String getConnectionId() { + return this.connectionId; + } + + /** + * This method is called when a message is read from the underlying {@link Socket} + * + * @param inputStream + * @param outputStream + * @return + * @throws Exception + */ + public abstract IoMessage visit(DataInputStream inputStream, DataOutputStream outputStream) throws Exception; + + /** + * This method is called when a message is to be sent to the underlying connected endpoint + * + * @param inputStream + * @param outputStream + * @param message + * @throws Exception + */ + public abstract void visit(DataInputStream inputStream, DataOutputStream outputStream, IoMessage message) + throws Exception; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/db/DbConnectionCheck.java b/li.strolch.utils/src/main/java/li/strolch/db/DbConnectionCheck.java new file mode 100644 index 000000000..8efd3e029 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/db/DbConnectionCheck.java @@ -0,0 +1,74 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.db; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Robert von Burg + */ +public class DbConnectionCheck { + + private static final Logger logger = LoggerFactory.getLogger(DbConnectionCheck.class); + private Map dsMap; + + /** + * @param dsMap + */ + public DbConnectionCheck(Map dsMap) { + this.dsMap = dsMap; + } + + /** + * Checks the connectivity to each of the configured {@link DbConnectionInfo} + * + * @throws DbException + */ + public void checkConnections() throws DbException { + Collection values = this.dsMap.values(); + for (DataSource ds : values) { + + logger.info("Checking connection " + ds); + + try (Connection con = ds.getConnection(); Statement st = con.createStatement();) { + + try (ResultSet rs = st.executeQuery("select version()")) { //$NON-NLS-1$ + if (rs.next()) { + logger.info(MessageFormat.format("Connected to: {0}", rs.getString(1))); //$NON-NLS-1$ + } + } + + } catch (SQLException e) { + String msg = "Failed to open DB connection to {0} due to: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, ds, e.getMessage()); + throw new DbException(msg, e); + } + } + + logger.info("All connections OK"); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/db/DbConstants.java b/li.strolch.utils/src/main/java/li/strolch/db/DbConstants.java new file mode 100644 index 000000000..fe1b2c9d4 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/db/DbConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.db; + +/** + * @author Robert von Burg + */ +public class DbConstants { + + public static final String PROP_DB_URL = "db.url"; //$NON-NLS-1$ + public static final String PROP_DB_IGNORE_REALM = "db.ignore.realm"; //$NON-NLS-1$ + public static final String PROP_DB_USERNAME = "db.username"; //$NON-NLS-1$ + public static final String PROP_DB_PASSWORD = "db.password"; //$NON-NLS-1$ + public static final String PROP_ALLOW_SCHEMA_CREATION = "allowSchemaCreation"; + public static final String PROP_ALLOW_SCHEMA_MIGRATION = "allowSchemaMigration"; + public static final String PROP_ALLOW_SCHEMA_DROP = "allowSchemaDrop"; + public static final String PROP_ALLOW_DATA_INIT_ON_SCHEMA_CREATE = "allowDataInitOnSchemaCreate"; + public static final String PROP_DB_VERSION = "db_version"; + public static final String RESOURCE_DB_VERSION = "/{0}_db_version.properties"; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/db/DbDataSourceBuilder.java b/li.strolch.utils/src/main/java/li/strolch/db/DbDataSourceBuilder.java new file mode 100644 index 000000000..aa5ada96c --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/db/DbDataSourceBuilder.java @@ -0,0 +1,28 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.db; + +import java.util.Properties; + +import javax.sql.DataSource; + +/** + * @author Robert von Burg + */ +public interface DbDataSourceBuilder { + + public DataSource build(String realm, String url, String username, String password, Properties properties); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/db/DbException.java b/li.strolch.utils/src/main/java/li/strolch/db/DbException.java new file mode 100644 index 000000000..78f420717 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/db/DbException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.db; + +/** + * @author Robert von Burg + */ +public class DbException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * @param message + */ + public DbException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public DbException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/db/DbMigrationState.java b/li.strolch.utils/src/main/java/li/strolch/db/DbMigrationState.java new file mode 100644 index 000000000..d88c4c7cd --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/db/DbMigrationState.java @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.db; + +/** + * @author Robert von Burg + */ +public enum DbMigrationState { + NOTHING, CREATED, MIGRATED, DROPPED_CREATED; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/db/DbSchemaVersionCheck.java b/li.strolch.utils/src/main/java/li/strolch/db/DbSchemaVersionCheck.java new file mode 100644 index 000000000..bf90c0691 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/db/DbSchemaVersionCheck.java @@ -0,0 +1,363 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.db; + +import static li.strolch.db.DbConstants.PROP_DB_VERSION; +import static li.strolch.db.DbConstants.RESOURCE_DB_VERSION; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.Version; +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.helper.FileHelper; + +/** + * @author Robert von Burg + */ +@SuppressWarnings(value = "nls") +public class DbSchemaVersionCheck { + + private static final Logger logger = LoggerFactory.getLogger(DbSchemaVersionCheck.class); + private String app; + private Class ctxClass; + private boolean allowSchemaCreation; + private boolean allowSchemaMigration; + private boolean allowSchemaDrop; + private Map dbMigrationStates; + + /** + * @param app + * @param ctxClass + * @param allowSchemaCreation + * @param allowSchemaDrop + */ + public DbSchemaVersionCheck(String app, Class ctxClass, boolean allowSchemaCreation, + boolean allowSchemaMigration, boolean allowSchemaDrop) { + + DBC.PRE.assertNotEmpty("app may not be empty!", app); + DBC.PRE.assertNotNull("ctxClass may not be null!", ctxClass); + + this.app = app; + this.ctxClass = ctxClass; + this.allowSchemaCreation = allowSchemaCreation; + this.allowSchemaMigration = allowSchemaMigration; + this.allowSchemaDrop = allowSchemaDrop; + this.dbMigrationStates = new HashMap<>(); + } + + /** + * @return the dbMigrationStates + */ + public Map getDbMigrationStates() { + return this.dbMigrationStates; + } + + public void checkSchemaVersion(Map dsMap) throws DbException { + for (Entry entry : dsMap.entrySet()) { + String realm = entry.getKey(); + DataSource ds = entry.getValue(); + DbMigrationState dbMigrationState = checkSchemaVersion(realm, ds); + this.dbMigrationStates.put(realm, dbMigrationState); + } + } + + /** + * Returns true if the schema existed or was only migrated, false if the schema was created + * + * @param ds + * @param realm2 + * + * @param connectionInfo + * + * @return true if the schema existed or was only migrated, false if the schema was created + * + * @throws DbException + */ + public DbMigrationState checkSchemaVersion(String realm, DataSource ds) throws DbException { + + logger.info(MessageFormat.format("[{0}:{1}] Checking Schema version for: {2}", this.app, realm, ds)); + + Version expectedDbVersion = getExpectedDbVersion(this.app, this.ctxClass); + + try (Connection con = ds.getConnection()) { + + // get current version + Version currentVersion = getCurrentVersion(con, this.app); + DbMigrationState migrationType = detectMigrationState(realm, expectedDbVersion, currentVersion); + + switch (migrationType) { + case CREATED: + createSchema(con, realm, expectedDbVersion); + break; + case MIGRATED: + migrateSchema(con, realm, expectedDbVersion); + break; + case DROPPED_CREATED: + throw new DbException("Migration type " + migrationType + " not handled!"); + case NOTHING: + // do nothing + default: + break; + } + + con.commit(); + return migrationType; + + } catch (SQLException e) { + String msg = "Failed to open DB connection to {0} due to: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, ds, e.getMessage()); + throw new DbException(msg, e); + } + } + + /** + * @param con + * @param app + * + * @return + * + * @throws SQLException + */ + public static Version getCurrentVersion(Connection con, String app) throws SQLException { + + // first see if we have any schema + String sql = "select table_schema, table_name, table_type from information_schema.tables where table_name = ?"; + try (PreparedStatement st = con.prepareStatement(sql)) { + st.setString(1, PROP_DB_VERSION); + if (!st.executeQuery().next()) + return null; + } + + // first find current version + sql = "select id, version from db_version where app = ? order by id desc;"; + Version currentVersion = null; + try (PreparedStatement st = con.prepareStatement(sql)) { + st.setString(1, app); + try (ResultSet rs = st.executeQuery()) { + if (rs.next()) + currentVersion = Version.valueOf(rs.getString(2)); + } + } + + return currentVersion; + } + + /** + * @param realm + * @param expectedDbVersion + * + * @return + * + * @throws SQLException + * @throws DbException + */ + public DbMigrationState detectMigrationState(String realm, Version expectedDbVersion, Version currentVersion) + throws SQLException, DbException { + + // no version, then we need to create it + if (currentVersion == null) + return DbMigrationState.CREATED; + + // otherwise parse the version + int compare = expectedDbVersion.compareTo(currentVersion); + if (compare == 0) { + String msg = "[{0}:{1}] Schema version {2} is the current version. No changes needed."; + msg = MessageFormat.format(msg, this.app, realm, currentVersion); + logger.info(msg); + return DbMigrationState.NOTHING; + } else if (compare > 0) { + String msg = "[{0}:{1}] Schema version is not current. Need to upgrade from {2} to {3}"; + msg = MessageFormat.format(msg, this.app, realm, currentVersion, expectedDbVersion); + logger.warn(msg); + return DbMigrationState.MIGRATED; + } + + throw new DbException(MessageFormat.format("[{0}:{1}]Current version {2} is later than expected version {3}", + this.app, realm, currentVersion, expectedDbVersion)); + } + + /** + * @param app + * @param ctxClass + * + * @return + * + * @throws DbException + */ + public static Version getExpectedDbVersion(String app, Class ctxClass) throws DbException { + Properties dbVersionProps = new Properties(); + + String dbVersionPropFile = MessageFormat.format(RESOURCE_DB_VERSION, app); + + try (InputStream stream = ctxClass.getResourceAsStream(dbVersionPropFile);) { + DBC.PRE.assertNotNull( + MessageFormat.format("Resource file with name {0} does not exist!", dbVersionPropFile), stream); + dbVersionProps.load(stream); + } catch (IOException e) { + String msg = "Expected resource file {0} does not exist or is not a valid properties file: {1}"; + msg = MessageFormat.format(msg, dbVersionPropFile, e.getMessage()); + throw new DbException(msg, e); + } + String dbVersion = dbVersionProps.getProperty(PROP_DB_VERSION); + String msg = "Missing property {0} in resource file {1}"; + DBC.PRE.assertNotEmpty(MessageFormat.format(msg, PROP_DB_VERSION, dbVersionPropFile), dbVersion); + + return Version.valueOf(dbVersion); + } + + /** + * @param scriptPrefix + * @param classLoader + * @param dbVersion + * @param type + * + * @return + * + * @throws DbException + */ + public static String getSql(String scriptPrefix, Class ctxClass, Version dbVersion, String type) + throws DbException { + String schemaResourceS = MessageFormat.format("/{0}_db_schema_{1}_{2}.sql", scriptPrefix, dbVersion, type); + try (InputStream stream = ctxClass.getResourceAsStream(schemaResourceS);) { + DBC.PRE.assertNotNull( + MessageFormat.format("Schema Resource file with name {0} does not exist!", schemaResourceS), + stream); + return FileHelper.readStreamToString(stream); + } catch (IOException e) { + throw new DbException("Schema creation resource file is missing or could not be read: " + schemaResourceS, + e); + } + } + + /** + * + * @param realm + * the realm to create the schema for (a {@link DbConnectionInfo} must exist for it) + * @param dbVersion + * the version to upgrade to + * @param st + * the open database {@link Statement} to which the SQL statements will be written + * + * @return true if the schema was created, false if it was not + * + * @throws DbException + */ + public void createSchema(Connection con, String realm, Version dbVersion) throws DbException { + + if (!this.allowSchemaCreation) { + String msg = "[{0}:{1}] No schema exists, or is not valid. Schema generation is disabled, thus can not continue!"; + msg = MessageFormat.format(msg, this.app, realm); + throw new DbException(msg); + } + + logger.info(MessageFormat.format("[{0}:{1}] Creating initial schema...", this.app, realm)); + + String sql = getSql(this.app, this.ctxClass, dbVersion, "initial"); + + try (Statement st = con.createStatement()) { + st.execute(sql); + } catch (SQLException e) { + logger.error("Failed to execute schema creation SQL: \n" + sql); + throw new DbException("Failed to execute schema generation SQL: " + e.getMessage(), e); + } + + logger.info(MessageFormat.format("[{0}:{1}] Successfully created schema with version {2}", this.app, realm, + dbVersion)); + } + + /** + * Upgrades the schema to the given version. If the current version is below the given version, then currently this + * method drops the schema and recreates it. Real migration must still be implemented + * + * @param realm + * the realm to migrate (a {@link DbConnectionInfo} must exist for it) + * @param dbVersion + * the version to upgrade to + * + * @return true if the schema was recreated, false if it was simply migrated + * + * @throws DbException + */ + public void migrateSchema(Connection con, String realm, Version dbVersion) throws DbException { + + if (!this.allowSchemaMigration) { + String msg = "[{0}:{1}] Schema is not valid. Schema migration is disabled, thus can not continue!"; + msg = MessageFormat.format(msg, this.app, realm); + throw new DbException(msg); + } + + logger.info(MessageFormat.format("[{0}:{1}] Migrating schema...", this.app, realm)); + + String sql = getSql(this.app, this.ctxClass, dbVersion, "migration"); + try (Statement st = con.createStatement()) { + st.execute(sql); + } catch (SQLException e) { + logger.error("Failed to execute schema migration SQL: \n" + sql); + throw new DbException("Failed to execute schema migration SQL: " + e.getMessage(), e); + } + + logger.info(MessageFormat.format("[{0}:{1}] Successfully migrated schema to version {2}", this.app, realm, + dbVersion)); + } + + /** + * @param realm + * the realm for which the schema must be dropped (a {@link DbConnectionInfo} must exist for it) + * @param dbVersion + * the version with which to to drop the schema + * @param st + * the open database {@link Statement} to which the SQL statements will be written + * + * @throws DbException + */ + public void dropSchema(Connection con, String realm, Version dbVersion) throws DbException { + + if (!this.allowSchemaDrop) { + String msg = "[{0}:{1}] Dropping Schema is disabled, but is required to upgrade current schema..."; + msg = MessageFormat.format(msg, this.app, realm); + throw new DbException(msg); + } + + logger.info(MessageFormat.format("[{0}:{1}] Dropping existing schema...", this.app, realm)); + + String sql = getSql(this.app, this.ctxClass, dbVersion, "drop"); + try (Statement st = con.createStatement()) { + st.execute(sql); + } catch (SQLException e) { + logger.error("Failed to execute schema drop SQL: \n" + sql); + throw new DbException("Failed to execute schema drop SQL: " + e.getMessage(), e); + } + + logger.info(MessageFormat.format("[{0}:{1}] Successfully dropped schema with version {2}", this.app, realm, + dbVersion)); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/fileserver/FileClient.java b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileClient.java new file mode 100644 index 000000000..8c0fd2dd8 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileClient.java @@ -0,0 +1,65 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.fileserver; + +import java.rmi.RemoteException; + +/** + * @author Robert von Burg + * + */ +public interface FileClient { + + /** + * Remote method with which a client can push parts of files to the server. It is up to the client to send as many + * parts as needed, the server will write the parts to the associated file + * + * @param filePart + * the part of the file + * @throws RemoteException + * if something goes wrong with the remote call + */ + public void uploadFilePart(FilePart filePart) throws RemoteException; + + /** + * Remote method with which a client can delete files from the server. It only deletes single files if they exist + * + * @param fileDeletion + * the {@link FileDeletion} defining the deletion request + * + * @return true if the file was deleted, false if the file did not exist + * + * @throws RemoteException + * if something goes wrong with the remote call + */ + public boolean deleteFile(FileDeletion fileDeletion) throws RemoteException; + + /** + * Remote method which a client can request part of a file. The server will fill the given {@link FilePart} with a + * byte array of the file, with bytes from the file, respecting the desired offset. It is up to the client to call + * this method multiple times for the entire file. It is a decision of the concrete implementation how much data is + * returned in each part, the client may pass a request, but this is not definitive + * + * @param filePart + * the part of the file + * + * @return the same file part, yet with the part of the file requested as a byte array + * + * @throws RemoteException + * if something goes wrong with the remote call + */ + public FilePart requestFile(FilePart filePart) throws RemoteException; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/fileserver/FileClientUtil.java b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileClientUtil.java new file mode 100644 index 000000000..c78f61456 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileClientUtil.java @@ -0,0 +1,238 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.fileserver; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.rmi.RemoteException; +import java.text.MessageFormat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + * + */ +public class FileClientUtil { + + private static final Logger logger = LoggerFactory.getLogger(FileClientUtil.class); + + /** + * @param rmiFileClient + * @param origFilePart + * @param dstFile + */ + public static void downloadFile(FileClient rmiFileClient, FilePart origFilePart, File dstFile) { + + // here we don't overwrite, the caller must make sure the destination file does not exist + if (dstFile.exists()) { + String msg = "The destination file {0} already exists. Delete it first, if you want to overwrite it!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, dstFile.getAbsolutePath()); + throw new RuntimeException(msg); + } + + try { + + FilePart tmpPart = origFilePart; + + int loops = 0; + int startLength = tmpPart.getPartLength(); + while (true) { + loops += 1; + + // get the next part + tmpPart = rmiFileClient.requestFile(tmpPart); + + // validate length of data + if (tmpPart.getPartLength() != tmpPart.getPartBytes().length) { + String msg = "Invalid tmpPart. Part length is not as long as the bytes passed {0} / {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, tmpPart.getPartLength(), tmpPart.getPartBytes().length); + throw new RuntimeException(msg); + } + + // validate offset is size of file + if (tmpPart.getPartOffset() != dstFile.length()) { + String msg = "The part offset $offset is not at the end of the file {0} / {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, tmpPart.getPartOffset(), dstFile.length()); + throw new RuntimeException(msg); + } + + // append the part + FileHelper.appendFilePart(dstFile, tmpPart.getPartBytes()); + + // update the offset + tmpPart.setPartOffset(tmpPart.getPartOffset() + tmpPart.getPartBytes().length); + + // break if the offset is past the length of the file + if (tmpPart.getPartOffset() >= tmpPart.getFileLength()) + break; + } + + String msg = "{0}: {1}: Requested {2} parts. StartSize: {3} EndSize: {4}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, tmpPart.getFileType(), tmpPart.getFileName(), loops, startLength, + tmpPart.getPartLength()); + logger.info(msg); + + // validate that the offset is at the end of the file + if (tmpPart.getPartOffset() != origFilePart.getFileLength()) { + msg = "Offset {0} is not at file length {1} after reading all the file parts!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, tmpPart.getPartOffset(), origFilePart.getFileLength()); + throw new RuntimeException(msg); + } + + // now validate hashes + String dstFileHash = StringHelper.getHexString(FileHelper.hashFileSha256(dstFile)); + if (!dstFileHash.equals(origFilePart.getFileHash())) { + msg = "Downloading the file {0} failed because the hashes don''t match. Expected: {1} / Actual: {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, origFilePart.getFileName(), origFilePart.getFileHash(), dstFileHash); + throw new RuntimeException(msg); + } + + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + String msg = "Downloading the file {0} failed because of an underlying exception {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, origFilePart.getFileName(), e.getLocalizedMessage()); + throw new RuntimeException(msg); + } + } + + /** + * @param rmiFileClient + * @param srcFile + * @param fileType + */ + public static void uploadFile(FileClient rmiFileClient, File srcFile, String fileType) { + + // make sure the source file exists + if (!srcFile.canRead()) { + String msg = MessageFormat.format("The source file does not exist at {0}", srcFile.getAbsolutePath()); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile));) { + + // get the size of the file + long fileLength = srcFile.length(); + String fileHash = StringHelper.getHexString(FileHelper.hashFileSha256(srcFile)); + + // create the file part to send + FilePart filePart = new FilePart(srcFile.getName(), fileType); + filePart.setFileLength(fileLength); + filePart.setFileHash(fileHash); + + // define the normal size of the parts we're sending. The last part will naturally have a different size + int partLength; + if (fileLength > FileHandler.MAX_PART_SIZE) + partLength = FileHandler.MAX_PART_SIZE; + else + partLength = (int) fileLength; + + // this is the byte array of data we're sending each time + byte[] bytes = new byte[partLength]; + + // open the stream to the file + int read = 0; + int offset = 0; + + // loop by reading the number of bytes needed for each part + int loops = 0; + int startLength = partLength; + while (true) { + loops += 1; + + // read the bytes into the array + read = inputStream.read(bytes); + + // validate we read the expected number of bytes + if (read == -1) + throw new IOException("Something went wrong while reading the bytes as -1 was returned!"); //$NON-NLS-1$ + if (read != bytes.length) { + String msg = "Something went wrong while reading the bytes as the wrong number of bytes were read. Expected {0} Actual: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, bytes.length, read); + throw new IOException(msg); + } + + // set the fields on the FilePart + filePart.setPartBytes(bytes); + filePart.setPartOffset(offset); + filePart.setPartLength(bytes.length); + + // and if this is the last part, then also set that + int nextOffset = offset + bytes.length; + if (nextOffset == fileLength) + filePart.setLastPart(true); + + // now send the part to the server + rmiFileClient.uploadFilePart(filePart); + + // if this was the last part, then break + if (filePart.isLastPart()) + break; + + // otherwise update the offset for the next part by also making sure the next part is not larger than + // the last part of the file + if (nextOffset + bytes.length > fileLength) { + long remaining = fileLength - nextOffset; + if (remaining > FileHandler.MAX_PART_SIZE) { + String msg = "Something went wrong as the remaining part {0} is larger than MAX_PART_SIZE {1}!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, remaining, FileHandler.MAX_PART_SIZE); + throw new RuntimeException(msg); + } + partLength = (int) remaining; + bytes = new byte[partLength]; + } + + // and save the offset for the next loop + offset = nextOffset; + } + + String msg = "{0}: {1}: Sent {2} parts. StartSize: {3} EndSize: {4}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, filePart.getFileType(), filePart.getFileName(), loops, startLength, + filePart.getPartLength()); + logger.info(msg); + + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + String msg = "Uploading the file {0} failed because of an underlying exception {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, srcFile.getAbsolutePath(), e.getLocalizedMessage()); + throw new RuntimeException(msg); + } + } + + /** + * @param rmiFileClient + * @param fileDeletion + * @param dstFile + */ + public static void deleteFile(FileClient rmiFileClient, FileDeletion fileDeletion, File dstFile) { + + try { + rmiFileClient.deleteFile(fileDeletion); + } catch (RemoteException e) { + String msg = "Deleting the file {0} failed because of an underlying exception {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, fileDeletion.getFileName(), e.getLocalizedMessage()); + throw new RuntimeException(msg); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/fileserver/FileDeletion.java b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileDeletion.java new file mode 100644 index 000000000..1954782b8 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileDeletion.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.fileserver; + +import java.io.Serializable; + +/** + * @author Robert von Burg + */ +public class FileDeletion implements Serializable { + + private static final long serialVersionUID = 1L; + + private String fileName; + private String fileType; + + /** + * @param fileName + * the name of the file to be deleted. This is either just the name, or a path relative to the type + * @param fileType + * the type of file to delete. This defines in which path the file resides + */ + public FileDeletion(String fileName, String fileType) { + this.fileName = fileName; + this.fileType = fileType; + } + + /** + * @return the fileType + */ + public String getFileType() { + return this.fileType; + } + + /** + * @return the fileName + */ + public String getFileName() { + return this.fileName; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/fileserver/FileHandler.java b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileHandler.java new file mode 100644 index 000000000..60bf99a4b --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/fileserver/FileHandler.java @@ -0,0 +1,307 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.fileserver; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.MessageFormat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; + +/** + * This class handles remote requests of clients to upload or download a file. Uploading a file is done by calling + * {@link #handleFilePart(FilePart)} and the downloading a file is done by calling {@link #requestFile(FilePart)} + * + * @author Robert von Burg + */ +public class FileHandler { + + private static final Logger logger = LoggerFactory.getLogger(FileHandler.class); + + /** + * DEF_PART_SIZE = default part size which is set to 1048576 bytes (1 MiB) + */ + public static final int MAX_PART_SIZE = 1048576; + + private String basePath; + private boolean verbose; + + /** + * + */ + public FileHandler(String basePath, boolean verbose) { + + File basePathF = new File(basePath); + if (!basePathF.exists()) { + String msg = MessageFormat.format("Base Path does not exist {0}", basePathF.getAbsolutePath()); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + if (!basePathF.canWrite()) { + String msg = MessageFormat.format("Can not write to base path {0}", basePathF.getAbsolutePath()); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + this.verbose = verbose; + this.basePath = basePath; + } + + /** + * Method which a client can request part of a file. The server will fill the given {@link FilePart} with a byte + * array of the file, with bytes from the file, respecting the desired offset. It is up to the client to call this + * method multiple times for the entire file. It is a decision of the concrete implementation how much data is + * returned in each part, the client may pass a request, but this is not definitive + * + * @param filePart + * the part of the file + */ + public FilePart requestFile(FilePart filePart) { + + // validate file name is legal + String fileName = filePart.getFileName(); + validateFileName(fileName); + + // validate type is legal + String fileType = filePart.getFileType(); + validateFileType(fileType); + + // evaluate the path where the file should reside + String fileTypePath = this.basePath + "/" + fileType; //$NON-NLS-1$ + File file = new File(fileTypePath, filePart.getFileName()); + + // now evaluate the file exists + String fileNotFoundMsg = "The file {0} could not be found in the location for files of type {1}"; //$NON-NLS-1$ + if (!file.canRead()) { + String msg = fileNotFoundMsg; + msg = MessageFormat.format(msg, fileName, fileType); + throw new RuntimeException(msg); + } + + // if this is the start of the file, then prepare the file part + long fileSize = file.length(); + if (filePart.getPartOffset() == 0) { + + // set the file length + filePart.setFileLength(fileSize); + + // set the SHA256 of the file + filePart.setFileHash(StringHelper.getHexString(FileHelper.hashFileSha256(file))); + } + + // variables defining the part of the file we're going to return + long requestOffset = filePart.getPartOffset(); + int requestSize = filePart.getPartLength(); + if (requestSize > FileHandler.MAX_PART_SIZE) { + String msg = "The requested part size {0} is greater than the allowed {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, requestSize, MAX_PART_SIZE); + throw new RuntimeException(msg); + } + + // validate lengths and offsets + if (filePart.getFileLength() != fileSize) { + String msg = "The part request has a file size {0}, but the file is actually {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, filePart.getFileLength(), fileSize); + throw new RuntimeException(msg); + } else if (requestOffset > fileSize) { + String msg = "The requested file part offset {0} is greater than the size of the file {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, requestOffset, fileSize); + throw new RuntimeException(msg); + } + // Otherwise make sure the offset + request length is not larger than the actual file size. + // If it is then this is the end part + else if (requestOffset + requestSize >= fileSize) { + + long remaining = fileSize - requestOffset; + + // update request size to last part of file + long l = Math.min(requestSize, remaining); + + // this is a fail safe + if (l > MAX_PART_SIZE) { + String msg = "Something went wrong. Min of requestSize and remaining is > MAX_PART_SIZE of {0}!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, MAX_PART_SIZE); + throw new RuntimeException(msg); + } + + // this is the size of the array we want to return + requestSize = (int) l; + filePart.setPartLength(requestSize); + filePart.setLastPart(true); + } + + // now read the part of the file and set it as bytes for the file part + try (FileInputStream fin = new FileInputStream(file);) { + + // position the stream + long skip = fin.skip(requestOffset); + if (skip != requestOffset) { + String msg = MessageFormat.format("Asked to skip {0} but only skipped {1}", requestOffset, skip); //$NON-NLS-1$ + throw new IOException(msg); + } + + // read the data + byte[] bytes = new byte[requestSize]; + int read = fin.read(bytes); + if (read != requestSize) { + String msg = MessageFormat.format("Asked to read {0} but only read {1}", requestSize, read); //$NON-NLS-1$ + throw new IOException(msg); + } + + // set the return result + filePart.setPartBytes(bytes); + + } catch (FileNotFoundException e) { + String msg = MessageFormat.format(fileNotFoundMsg, fileName, fileType); + throw new RuntimeException(msg); + } catch (IOException e) { + String msg = "There was an error while reading from the file {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, fileName); + throw new RuntimeException(msg); + } + + // we are returning the same object as the user gave us, just modified + if (this.verbose) { + String msg = "Read {0} for file {1}/{2}"; //$NON-NLS-1$ + String fileSizeS = FileHelper.humanizeFileSize(filePart.getPartBytes().length); + msg = MessageFormat.format(msg, fileSizeS, fileType, fileName); + logger.info(msg); + } + return filePart; + } + + /** + * Method with which a client can push parts of files to the server. It is up to the client to send as many parts as + * needed, the server will write the parts to the associated file + * + * @param filePart + * the part of the file + */ + public void handleFilePart(FilePart filePart) { + + // validate file name is legal + String fileName = filePart.getFileName(); + validateFileName(fileName); + + // validate type is legal + String fileType = filePart.getFileType(); + validateFileType(fileType); + + // evaluate the path where the file should reside + String fileTypePath = this.basePath + "/" + fileType; //$NON-NLS-1$ + File dstFile = new File(fileTypePath, filePart.getFileName()); + + // if the file already exists, then this may not be a start part + if (filePart.getPartOffset() == 0 && dstFile.exists()) { + String msg = "The file {0} already exist for type {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, fileName, fileType); + throw new RuntimeException(msg); + } + + // write the part + FileHelper.appendFilePart(dstFile, filePart.getPartBytes()); + + // if this is the last part, then validate the hashes + if (filePart.isLastPart()) { + String dstFileHash = StringHelper.getHexString(FileHelper.hashFileSha256(dstFile)); + if (!dstFileHash.equals(filePart.getFileHash())) { + String msg = "Uploading the file {0} failed because the hashes don''t match. Expected: {1} / Actual: {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, filePart.getFileName(), filePart.getFileHash(), dstFileHash); + throw new RuntimeException(msg); + } + } + + if (this.verbose) { + String msg; + if (filePart.isLastPart()) + msg = "Wrote {0} for part of file {1}/{2}"; //$NON-NLS-1$ + else + msg = "Wrote {0} for last part of file {1}/{2}"; //$NON-NLS-1$ + String fileSizeS = FileHelper.humanizeFileSize(filePart.getPartBytes().length); + msg = MessageFormat.format(msg, fileSizeS, fileType, fileName); + logger.info(msg); + } + } + + /** + * Method with which a client can delete files from the server. It only deletes single files if they exist + * + * @param fileDeletion + * the {@link FileDeletion} defining the deletion request + * + * @return true if the file was deleted, false if the file did not exist + * + */ + public boolean deleteFile(FileDeletion fileDeletion) { + + // validate file name is legal + String fileName = fileDeletion.getFileName(); + validateFileName(fileName); + + // validate type is legal + String fileType = fileDeletion.getFileType(); + validateFileType(fileType); + + // evaluate the path where the file should reside + String fileTypePath = this.basePath + "/" + fileType; //$NON-NLS-1$ + File fileToDelete = new File(fileTypePath, fileDeletion.getFileName()); + + // delete the file + boolean deletedFile = FileHelper.deleteFiles(new File[] { fileToDelete }, true); + + String msg; + if (deletedFile) + msg = "Deleted file {1}/{2}"; //$NON-NLS-1$ + else + msg = "Failed to delete file {1}/{2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, fileType, fileName); + logger.info(msg); + return deletedFile; + } + + /** + * Validates that the file name is legal, i.e. not empty or contains references up the tree + * + * @param fileName + */ + private void validateFileName(String fileName) { + + if (fileName == null || fileName.isEmpty()) { + throw new RuntimeException("The file name was not given! Can not find a file without a name!"); //$NON-NLS-1$ + } else if (fileName.contains("/")) { //$NON-NLS-1$ + String msg = "The given file name contains illegal characters. The file name may not contain slashes!"; //$NON-NLS-1$ + throw new RuntimeException(msg); + } + } + + /** + * Validates that the file type is legal, i.e. not empty or contains references up the tree + * + * @param fileType + */ + private void validateFileType(String fileType) { + if (fileType == null || fileType.isEmpty()) { + throw new RuntimeException("The file type was not given! Can not find a file without a type!"); //$NON-NLS-1$ + } else if (fileType.contains("/")) { //$NON-NLS-1$ + String msg = "The given file type contains illegal characters. The file type may not contain slashes!"; //$NON-NLS-1$ + throw new RuntimeException(msg); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/fileserver/FilePart.java b/li.strolch.utils/src/main/java/li/strolch/fileserver/FilePart.java new file mode 100644 index 000000000..9101ca833 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/fileserver/FilePart.java @@ -0,0 +1,161 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.fileserver; + +import java.io.Serializable; + +/** + * @author Robert von Burg + */ +public class FilePart implements Serializable { + + private static final long serialVersionUID = 1L; + + private String fileName; + private long fileLength; + private String fileHash; + private String fileType; + + private long partOffset; + private int partLength; + private byte[] partBytes; + private boolean lastPart; + + /** + * @param fileName + * the name of the file being referenced. This is either just the name, or a path relative to the type + * @param fileType + * defines the type of file being uploaded or retrieved. This defines in which path the file resides + */ + public FilePart(String fileName, String fileType) { + + if (fileName == null || fileName.isEmpty()) + throw new RuntimeException("fileName may not be empty!"); //$NON-NLS-1$ + if (fileType == null || fileType.isEmpty()) + throw new RuntimeException("fileType may not be empty!"); //$NON-NLS-1$ + + this.fileName = fileName; + this.fileType = fileType; + + this.partOffset = 0; + this.partLength = FileHandler.MAX_PART_SIZE; + this.partBytes = null; + } + + /** + * @return the fileLength + */ + public long getFileLength() { + return this.fileLength; + } + + /** + * @param fileLength + * the fileLength to set + */ + public void setFileLength(long fileLength) { + this.fileLength = fileLength; + } + + /** + * @return the fileHash + */ + public String getFileHash() { + return this.fileHash; + } + + /** + * @param fileHash + * the fileHash to set + */ + public void setFileHash(String fileHash) { + this.fileHash = fileHash; + } + + /** + * @return the fileType + */ + public String getFileType() { + return this.fileType; + } + + /** + * @return the partOffset + */ + public long getPartOffset() { + return this.partOffset; + } + + /** + * @param partOffset + * the partOffset to set + */ + public void setPartOffset(long partOffset) { + this.partOffset = partOffset; + } + + /** + * @return the partLength + */ + public int getPartLength() { + return this.partLength; + } + + /** + * @param partLength + * the partLength to set + */ + public void setPartLength(int partLength) { + this.partLength = partLength; + } + + /** + * @return the partBytes + */ + public byte[] getPartBytes() { + return this.partBytes; + } + + /** + * @param partBytes + * the partBytes to set + */ + public void setPartBytes(byte[] partBytes) { + this.partBytes = partBytes; + } + + /** + * @return the lastPart + */ + public boolean isLastPart() { + return this.lastPart; + } + + /** + * @param lastPart + * the lastPart to set + */ + public void setLastPart(boolean lastPart) { + this.lastPart = lastPart; + } + + /** + * @return the fileName + */ + public String getFileName() { + return this.fileName; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/StringMatchMode.java b/li.strolch.utils/src/main/java/li/strolch/utils/StringMatchMode.java new file mode 100644 index 000000000..a58bd7226 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/StringMatchMode.java @@ -0,0 +1,125 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils; + +import li.strolch.utils.dbc.DBC; + +/** + * @author Robert von Burg + */ +public enum StringMatchMode { + EQUALS_CASE_SENSITIVE(true, true), + EQUALS_CASE_INSENSITIVE(true, false), + CONTAINS_CASE_SENSITIVE(false, true), + CONTAINS_CASE_INSENSITIVE(false, false); + + private final boolean equals; + private final boolean caseSensitve; + + private StringMatchMode(boolean equals, boolean caseSensitive) { + this.equals = equals; + this.caseSensitve = caseSensitive; + } + + /** + * @return the caseSensitve + */ + public boolean isCaseSensitve() { + return this.caseSensitve; + } + + /** + * @return the equals + */ + public boolean isEquals() { + return this.equals; + } + + public boolean matches(String value1, String value2) { + DBC.PRE.assertNotNull("value1 must be set!", value1); //$NON-NLS-1$ + DBC.PRE.assertNotNull("value2 must be set!", value2); //$NON-NLS-1$ + if (!isEquals() && !isCaseSensitve()) + return value1.toLowerCase().contains(value2.toLowerCase()); + + if (!isCaseSensitve()) + return value1.toLowerCase().equals(value2.toLowerCase()); + + if (!isEquals()) + return value1.contains(value2); + + return value1.equals(value2); + } + + /** + *

+ * Returns {@link StringMatchMode#EQUALS_CASE_SENSITIVE} + *

+ * + *

+ * Short method, useful for static imports, or simply for shorter code + *

+ * + * @return {@link StringMatchMode#EQUALS_CASE_SENSITIVE} + */ + public static StringMatchMode es() { + return EQUALS_CASE_SENSITIVE; + } + + /** + *

+ * Returns {@link #EQUALS_CASE_INSENSITIVE} + *

+ * + *

+ * Short method, useful for static imports, or simply for shorter code + *

+ * + * @return {@link #EQUALS_CASE_INSENSITIVE} + */ + public static StringMatchMode ei() { + return EQUALS_CASE_INSENSITIVE; + } + + /** + *

+ * Returns {@link #CONTAINS_CASE_SENSITIVE} + *

+ * + *

+ * Short method, useful for static imports, or simply for shorter code + *

+ * + * @return {@link #CONTAINS_CASE_SENSITIVE} + */ + public static StringMatchMode cs() { + return CONTAINS_CASE_SENSITIVE; + } + + /** + *

+ * Returns {@link #CONTAINS_CASE_INSENSITIVE} + *

+ * + *

+ * Short method, useful for static imports, or simply for shorter code + *

+ * + * @return {@link #CONTAINS_CASE_INSENSITIVE} + */ + public static StringMatchMode ci() { + return CONTAINS_CASE_INSENSITIVE; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/Version.java b/li.strolch.utils/src/main/java/li/strolch/utils/Version.java new file mode 100644 index 000000000..e7eabc1d6 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/Version.java @@ -0,0 +1,507 @@ +package li.strolch.utils; + +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import li.strolch.utils.helper.StringHelper; + +/** + * This class has been adapted from org.osgi.framework.Version + * + * Version identifier. + * + *

+ * Version identifiers have four components. + *

    + *
  1. Major version. A non-negative integer.
  2. + *
  3. Minor version. A non-negative integer.
  4. + *
  5. Micro version. A non-negative integer.
  6. + *
  7. Qualifier. A text string. See {@code Version(String)} for the format of the qualifier string.
  8. + *
+ * + * Note: The qualifier can be separated by two different styles: {@link #OSGI_QUALIFIER_SEPARATOR} or + * {@link #MAVEN_QUALIFIER_SEPARATOR}. Thus the qualifier my also have two special values: + * {@link #OSGI_SNAPSHOT_QUALIFIER} or {@value #MAVEN_SNAPSHOT_QUALIFIER}. + * + *

+ * The grammar for parsing version strings is as follows: + * + *

+ * version ::= major('.'minor('.'micro('.'qualifier)?)?)?
+ * major ::= digit+
+ * minor ::= digit+
+ * micro ::= digit+
+ * qualifier ::= (alpha|digit|'_'|'-')+
+ * digit ::= [0..9]
+ * alpha ::= [a..zA..Z]
+ * 
+ * + * Note: There must be no whitespace in version. + *

+ * + *

+ * Note: {@code Version} objects are immutable and thus thread safe + *

+ */ +public class Version implements Comparable { + + public static final String SEPARATOR = "."; + public static final String OSGI_QUALIFIER_SEPARATOR = "."; + public static final String MAVEN_QUALIFIER_SEPARATOR = "-"; + + public static final String MAVEN_SNAPSHOT_QUALIFIER = "SNAPSHOT"; + public static final String OSGI_SNAPSHOT_QUALIFIER = "qualifier"; + + private final int major; + private final int minor; + private final int micro; + private final String qualifier; + + private transient String versionString; + private boolean osgiStyle; + + /** + * The empty version "0.0.0". + */ + public static final Version emptyVersion = new Version(0, 0, 0); + + /** + * Creates a version identifier from the specified numerical components. This instance will have + * {@link #isOsgiStyle()} return false + * + *

+ * The qualifier is set to the empty string. + * + * @param major + * Major component of the version identifier. + * @param minor + * Minor component of the version identifier. + * @param micro + * Micro component of the version identifier. + * @throws IllegalArgumentException + * If the numerical components are negative. + */ + public Version(final int major, final int minor, final int micro) { + this(major, minor, micro, null); + } + + /** + * Creates a version identifier from the specified components. This instance will have {@link #isOsgiStyle()} return + * false + * + * @param major + * Major component of the version identifier. + * @param minor + * Minor component of the version identifier. + * @param micro + * Micro component of the version identifier. + * @param qualifier + * Qualifier component of the version identifier. If {@code null} is specified, then the qualifier will + * be set to the empty string. + * + * @throws IllegalArgumentException + * If the numerical components are negative or the qualifier string is invalid. + */ + public Version(final int major, final int minor, final int micro, String qualifier) { + this(major, minor, micro, null, false); + } + + /** + * Creates a version identifier from the specified components. + * + * @param major + * Major component of the version identifier. + * @param minor + * Minor component of the version identifier. + * @param micro + * Micro component of the version identifier. + * @param qualifier + * Qualifier component of the version identifier. If {@code null} is specified, then the qualifier will + * be set to the empty string. + * @param osgiStyle + * if true, then this is an osgi style version, otherwise not + * + * @throws IllegalArgumentException + * If the numerical components are negative or the qualifier string is invalid. + */ + public Version(final int major, final int minor, final int micro, String qualifier, boolean osgiStyle) { + this.major = major; + this.minor = minor; + this.micro = micro; + this.qualifier = qualifier == null ? "" : qualifier; + this.versionString = null; + validate(); + } + + /** + *

+ * Creates a version identifier from the specified string. + *

+ * + * @param version + * String representation of the version identifier. + * + * @throws IllegalArgumentException + * If {@code version} is improperly formatted. + */ + private Version(final String version) { + int maj = 0; + int min = 0; + int mic = 0; + String qual = StringHelper.EMPTY; + + try { + StringTokenizer st = new StringTokenizer(version, + SEPARATOR + MAVEN_QUALIFIER_SEPARATOR + OSGI_QUALIFIER_SEPARATOR, true); + maj = Integer.parseInt(st.nextToken()); + + if (st.hasMoreTokens()) { // minor + st.nextToken(); // consume delimiter + min = Integer.parseInt(st.nextToken()); + + if (st.hasMoreTokens()) { // micro + st.nextToken(); // consume delimiter + mic = Integer.parseInt(st.nextToken()); + + if (st.hasMoreTokens()) { // qualifier + + String qualifierSeparator = st.nextToken(); // consume delimiter + this.osgiStyle = qualifierSeparator.equals(OSGI_QUALIFIER_SEPARATOR); + + qual = st.nextToken(StringHelper.EMPTY); // remaining string + + if (st.hasMoreTokens()) { // fail safe + throw new IllegalArgumentException("invalid format: " + version); + } + } + } + } + } catch (NoSuchElementException e) { + IllegalArgumentException iae = new IllegalArgumentException("invalid format: " + version); + iae.initCause(e); + throw iae; + } + + this.major = maj; + this.minor = min; + this.micro = mic; + this.qualifier = qual; + this.versionString = null; + validate(); + } + + /** + * Called by the Version constructors to validate the version components. + * + * @throws IllegalArgumentException + * If the numerical components are negative or the qualifier string is invalid. + */ + private void validate() { + if (this.major < 0) { + throw new IllegalArgumentException("negative major"); + } + if (this.minor < 0) { + throw new IllegalArgumentException("negative minor"); + } + if (this.micro < 0) { + throw new IllegalArgumentException("negative micro"); + } + char[] chars = this.qualifier.toCharArray(); + for (char ch : chars) { + if (('A' <= ch) && (ch <= 'Z')) { + continue; + } + if (('a' <= ch) && (ch <= 'z')) { + continue; + } + if (('0' <= ch) && (ch <= '9')) { + continue; + } + if ((ch == '_') || (ch == '-')) { + continue; + } + throw new IllegalArgumentException("invalid qualifier: " + this.qualifier); + } + } + + public Boolean isFullyQualified() { + return !this.qualifier.isEmpty(); + } + + /** + * Parses a version identifier from the specified string. + * + *

+ * See {@code Version(String)} for the format of the version string. + * + * @param version + * String representation of the version identifier. Leading and trailing whitespace will be ignored. + * + * @return A {@code Version} object representing the version identifier. If {@code version} is {@code null} or the + * empty string then {@code emptyVersion} will be returned. + * + * @throws IllegalArgumentException + * If {@code version} is improperly formatted. + */ + public static Version valueOf(String version) { + if (version == null) + return emptyVersion; + + String trimmedVersion = version.trim(); + if (trimmedVersion.length() == 0) + return emptyVersion; + + return new Version(trimmedVersion); + } + + /** + * Returns true if the given version string can be parsed, meaning a {@link Version} instance can be instantiated + * with it + * + * @param version + * String representation of the version identifier. Leading and trailing whitespace will be ignored. + * + * @return true if no parse errors occurr + */ + public static boolean isParseable(String version) { + try { + valueOf(version); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + + /** + * Returns the major component of this version identifier. + * + * @return The major component. + */ + public int getMajor() { + return this.major; + } + + /** + * Returns the minor component of this version identifier. + * + * @return The minor component. + */ + public int getMinor() { + return this.minor; + } + + /** + * Returns the micro component of this version identifier. + * + * @return The micro component. + */ + public int getMicro() { + return this.micro; + } + + /** + * Returns the qualifier component of this version identifier. + * + * @return The qualifier component. + */ + public String getQualifier() { + return this.qualifier; + } + + /** + * Returns a new {@link Version} where each version number is incremented or decreased by the given parameters + * + * @param major + * the value to increase or decrease the major part of the version + * @param minor + * the value to increase or decrease the minor part of the version + * @param micro + * the value to increase or decrease the micro part of the version + * + * @return the new Version with the version parts modified as passed in by the parameters + */ + public Version add(int major, int minor, int micro) { + return new Version(this.major + major, this.minor + minor, this.micro + micro, this.qualifier, this.osgiStyle); + } + + /** + * @return true if this is an OSGI style version, i.e. if has a qualifier, then osgi defines how the qualifier is + * appended to the version + */ + public boolean isOsgiStyle() { + return this.osgiStyle; + } + + /** + * @return true if this version is for a snapshot version, i.e. ends with {@link #MAVEN_SNAPSHOT_QUALIFIER} or + * {@link #OSGI_SNAPSHOT_QUALIFIER} + */ + public boolean isSnapshot() { + return MAVEN_SNAPSHOT_QUALIFIER.equals(this.qualifier) || OSGI_SNAPSHOT_QUALIFIER.equals(this.qualifier); + } + + /** + * Returns a hash code value for the object. + * + * @return An integer which is a hash code value for this object. + */ + @Override + public int hashCode() { + return (this.major << 24) + (this.minor << 16) + (this.micro << 8) + this.qualifier.hashCode(); + } + + /** + * Compares this {@code Version} object to another object. + * + *

+ * A version is considered to be equal to another version if the major, minor and micro components are equal + * and the qualifier component is equal (using {@code String.equals}). + * + * @param object + * The {@code Version} object to be compared. + * @return {@code true} if {@code object} is a {@code Version} and is equal to this object; {@code false} otherwise. + */ + @Override + public boolean equals(final Object object) { + if (object == this) + return true; + if (!(object instanceof Version)) + return false; + + Version other = (Version) object; + return (this.major == other.major) && (this.minor == other.minor) && (this.micro == other.micro) + && this.qualifier.equals(other.qualifier); + } + + /** + * Compares this {@code Version} object to another object ignoring the qualifier part. + * + *

+ * A version is considered to be equal to another version if the major, minor and micro components are + * equal. + * + * @param object + * The {@code Version} object to be compared. + * @return {@code true} if {@code object} is a {@code Version} and is equal to this object; {@code false} otherwise. + */ + public boolean equalsIgnoreQualifier(final Object object) { + if (object == this) + return true; + if (!(object instanceof Version)) + return false; + + Version other = (Version) object; + return (this.major == other.major) && (this.minor == other.minor) && (this.micro == other.micro); + } + + /** + * Compares this {@code Version} object to another {@code Version}. + * + *

+ * A version is considered to be less than another version if its major component is less than the other + * version's major component, or the major components are equal and its minor component is less than the other + * version's minor component, or the major and minor components are equal and its micro component is less than the + * other version's micro component, or the major, minor and micro components are equal and it's qualifier component + * is less than the other version's qualifier component (using {@code String.compareTo}). + * + *

+ * A version is considered to be equal to another version if the major, minor and micro components are equal + * and the qualifier component is equal (using {@code String.compareTo}). + * + * @param other + * The {@code Version} object to be compared. + * @return A negative integer, zero, or a positive integer if this version is less than, equal to, or greater than + * the specified {@code Version} object. + * @throws ClassCastException + * If the specified object is not a {@code Version} object. + */ + @Override + public int compareTo(final Version other) { + if (other == this) + return 0; + + int result = this.major - other.major; + if (result != 0) + return result; + + result = this.minor - other.minor; + if (result != 0) + return result; + + result = this.micro - other.micro; + if (result != 0) + return result; + + return this.qualifier.compareTo(other.qualifier); + } + + /** + * Returns the string representation of this version identifier. + * + *

+ * The format of the version string will be {@code major.minor.micro} if qualifier is the empty string or + * {@code major.minor.micro.qualifier} otherwise. + * + * @return The string representation of this version identifier. + */ + @Override + public String toString() { + if (this.versionString == null) + this.versionString = toString(this.osgiStyle); + return this.versionString; + } + + private String toString(final boolean withOsgiStyle) { + int q = this.qualifier.length(); + StringBuilder result = new StringBuilder(20 + q); + result.append(this.major); + result.append(SEPARATOR); + result.append(this.minor); + result.append(SEPARATOR); + result.append(this.micro); + if (q > 0) { + if (withOsgiStyle) { + result.append(OSGI_QUALIFIER_SEPARATOR); + } else { + result.append(MAVEN_QUALIFIER_SEPARATOR); + } + result.append(createQualifier(withOsgiStyle)); + } + return result.toString(); + } + + private String createQualifier(boolean withOsgiStyle) { + if (this.qualifier.equals(MAVEN_SNAPSHOT_QUALIFIER) || this.qualifier.equals(OSGI_SNAPSHOT_QUALIFIER)) { + if (withOsgiStyle) + return OSGI_SNAPSHOT_QUALIFIER; + return MAVEN_SNAPSHOT_QUALIFIER; + } + + return this.qualifier; + } + + /** + * @return This version represented in a maven compatible form. + */ + public String toMavenStyleString() { + return toString(false); + } + + /** + * @return This version represented in an OSGi compatible form. + */ + public String toOsgiStyleString() { + return toString(true); + } + + /** + * @return This only the major and minor version in a string + */ + public String toMajorAndMinorString() { + StringBuilder result = new StringBuilder(20); + result.append(this.major); + result.append(SEPARATOR); + result.append(this.minor); + return result.toString(); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/DateRange.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/DateRange.java new file mode 100644 index 000000000..6f2f196ad --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/DateRange.java @@ -0,0 +1,133 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import java.util.Date; + +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.iso8601.ISO8601FormatFactory; + +/** + * @author Robert von Burg + */ +public class DateRange { + + private boolean fromInclusive; + private boolean toInclusive; + private Date fromDate; + private Date toDate; + + public DateRange from(Date from, boolean inclusive) { + this.fromDate = from; + this.fromInclusive = inclusive; + validate(); + return this; + } + + public DateRange to(Date to, boolean inclusive) { + this.toDate = to; + this.toInclusive = inclusive; + validate(); + return this; + } + + private void validate() { + if (this.toDate != null && this.fromDate != null) + DBC.INTERIM.assertTrue("From must be before to!", this.toDate.compareTo(this.fromDate) >= 0); //$NON-NLS-1$ + } + + /** + * @return from date + */ + public Date getFromDate() { + return this.fromDate; + } + + /** + * @return to date + */ + public Date getToDate() { + return this.toDate; + } + + /** + * @return true if from is set + */ + public boolean isFromBounded() { + return this.fromDate != null; + } + + /** + * @return true if to is set + */ + public boolean isToBounded() { + return this.toDate != null; + } + + /** + * @return true if both from and to are null + */ + public boolean isUnbounded() { + return this.fromDate == null && this.toDate == null; + } + + /** + * @return true if both from and to date are set + */ + public boolean isBounded() { + return this.fromDate != null && this.toDate != null; + } + + /** + * @return true if both from and to date are set and they are both equal + */ + public boolean isDate() { + return isBounded() && this.fromDate.equals(this.toDate); + } + + public boolean contains(Date date) { + DBC.PRE.assertNotNull("Date must be given!", date); //$NON-NLS-1$ + if (this.fromDate == null && this.toDate == null) + return true; + + boolean fromContains = true; + boolean toContains = true; + + if (this.toDate != null) { + int compare = this.toDate.compareTo(date); + if (this.toInclusive) + toContains = compare >= 0; + else + toContains = compare > 0; + } + + if (this.fromDate != null) { + int compare = this.fromDate.compareTo(date); + if (this.fromInclusive) + fromContains = compare <= 0; + else + fromContains = compare < 0; + } + return toContains && fromContains; + } + + @Override + public String toString() { + ISO8601FormatFactory df = ISO8601FormatFactory.getInstance(); + return df.formatDate(this.fromDate) + (this.fromInclusive ? " (inc)" : " (exc)") + " - " + + df.formatDate(this.toDate) + (this.toInclusive ? " (inc)" : " (exc)"); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/DefaultedHashMap.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/DefaultedHashMap.java new file mode 100644 index 000000000..4f3de0c2b --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/DefaultedHashMap.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Robert von Burg + */ +public class DefaultedHashMap extends HashMap { + + private static final long serialVersionUID = 1L; + private V defaultValue; + + /** + * Constructs this {@link Map} instance to have a default value on inexistent keys + * + * @param defaultValue + * the default to return if a key is not mapped + */ + public DefaultedHashMap(V defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public V get(Object key) { + return getOrDefault(key, this.defaultValue); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java new file mode 100644 index 000000000..a656e9f72 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java @@ -0,0 +1,124 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * @author Robert von Burg + */ +public class MapOfLists { + + private Map> mapOfLists; + + public MapOfLists() { + this.mapOfLists = new HashMap<>(); + } + + public Set keySet() { + return this.mapOfLists.keySet(); + } + + public List getList(T t) { + return this.mapOfLists.get(t); + } + + public boolean addElement(T t, U u) { + List list = this.mapOfLists.get(t); + if (list == null) { + list = new ArrayList<>(); + this.mapOfLists.put(t, list); + } + return list.add(u); + } + + public boolean addList(T t, List u) { + List list = this.mapOfLists.get(t); + if (list == null) { + list = new ArrayList<>(); + this.mapOfLists.put(t, list); + } + return list.addAll(u); + } + + public boolean removeElement(T t, U u) { + List list = this.mapOfLists.get(t); + if (list == null) { + return false; + } + boolean removed = list.remove(u); + if (list.isEmpty()) { + this.mapOfLists.remove(t); + } + + return removed; + } + + public List removeList(T t) { + return this.mapOfLists.remove(t); + } + + public void clear() { + Set>> entrySet = this.mapOfLists.entrySet(); + Iterator>> iter = entrySet.iterator(); + while (iter.hasNext()) { + iter.next().getValue().clear(); + iter.remove(); + } + } + + public boolean containsList(T t) { + return this.mapOfLists.containsKey(t); + } + + public boolean containsElement(T t, U u) { + List list = this.mapOfLists.get(t); + if (list == null) + return false; + return list.contains(u); + } + + public int sizeKeys() { + return this.mapOfLists.size(); + } + + public int size() { + int size = 0; + Set>> entrySet = this.mapOfLists.entrySet(); + Iterator>> iter = entrySet.iterator(); + while (iter.hasNext()) { + size += iter.next().getValue().size(); + } + return size; + } + + public int size(T t) { + List list = this.mapOfLists.get(t); + if (list.size() == 0) + return 0; + return list.size(); + } + + public boolean isEmpty() { + return this.mapOfLists.isEmpty(); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java new file mode 100644 index 000000000..388352cab --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java @@ -0,0 +1,172 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + *

+ * Collection to store a tree with a depth of 3 elements. This solves having to always write the declaration: + *

+ * + *
+ * Map<String, Map&lgt;String, MyObject>> mapOfMaps = new HashMap<>;
+ * 
+ * + *

+ * As an example to persist a map of MyObject where the branches are String one would write it as follows: + *

+ * + *
+ * MapOfMaps<String, String, MyObject> mapOfMaps = new MapOfMaps<>();
+ * 
+ * + * + * @author Robert von Burg + * + * @param + * The key to a map with U as the key and V as the value + * @param + * The key to get a value (leaf) + * @param + * The value stored in the tree (leaf) + */ +public class MapOfMaps { + + private Map> mapOfMaps; + + public MapOfMaps() { + this.mapOfMaps = new HashMap<>(); + } + + public Set keySet() { + return this.mapOfMaps.keySet(); + } + + public Map getMap(T t) { + return this.mapOfMaps.get(t); + } + + public V getElement(T t, U u) { + Map map = this.mapOfMaps.get(t); + if (map == null) + return null; + return map.get(u); + } + + public V addElement(T t, U u, V v) { + Map map = this.mapOfMaps.get(t); + if (map == null) { + map = new HashMap<>(); + this.mapOfMaps.put(t, map); + } + return map.put(u, v); + } + + public List getAllElements() { + List all = new ArrayList<>(); + for (Map u : this.mapOfMaps.values()) { + all.addAll(u.values()); + } + return all; + } + + public List getAllElements(T t) { + List all = new ArrayList<>(); + Map map = this.mapOfMaps.get(t); + if (map != null) { + all.addAll(map.values()); + } + return all; + } + + public void addMap(T t, Map u) { + Map map = this.mapOfMaps.get(t); + if (map == null) { + map = new HashMap<>(); + this.mapOfMaps.put(t, map); + } + map.putAll(u); + } + + public V removeElement(T t, U u) { + Map map = this.mapOfMaps.get(t); + if (map == null) { + return null; + } + V v = map.remove(u); + if (map.isEmpty()) { + this.mapOfMaps.remove(t); + } + + return v; + } + + public Map removeMap(T t) { + return this.mapOfMaps.remove(t); + } + + public void clear() { + Set>> entrySet = this.mapOfMaps.entrySet(); + Iterator>> iter = entrySet.iterator(); + while (iter.hasNext()) { + iter.next().getValue().clear(); + iter.remove(); + } + } + + public boolean containsMap(T t) { + return this.mapOfMaps.containsKey(t); + } + + public boolean containsElement(T t, U u) { + Map map = this.mapOfMaps.get(t); + if (map == null) + return false; + return map.containsKey(u); + } + + public int sizeKeys() { + return this.mapOfMaps.size(); + } + + public int size() { + int size = 0; + Set>> entrySet = this.mapOfMaps.entrySet(); + Iterator>> iter = entrySet.iterator(); + while (iter.hasNext()) { + size += iter.next().getValue().size(); + } + return size; + } + + public int size(T t) { + Map map = this.mapOfMaps.get(t); + if (map == null) + return 0; + return map.size(); + } + + public boolean isEmpty() { + return this.mapOfMaps.isEmpty(); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java new file mode 100644 index 000000000..335ad05a1 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java @@ -0,0 +1,127 @@ +/* + * Copyright 2015 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import java.util.List; + +/** + * @author Robert von Burg + */ +public class Paging { + + private int pageSize; + private int pageToReturn; + private int nrOfPages; + private int nrOfElements; + + private List input; + private List page; + + private Paging(int pageSize, int indexOfPageToReturn) { + this.pageSize = pageSize; + this.pageToReturn = indexOfPageToReturn; + } + + public int getPageSize() { + return this.pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public int getPageToReturn() { + return this.pageToReturn; + } + + public void setPageToReturn(int pageToReturn) { + this.pageToReturn = pageToReturn; + } + + public int getNrOfPages() { + return this.nrOfPages; + } + + public void setNrOfPages(int nrOfPages) { + this.nrOfPages = nrOfPages; + } + + public int getNrOfElements() { + return this.nrOfElements; + } + + public void setNrOfElements(int nrOfElements) { + this.nrOfElements = nrOfElements; + } + + public List getInput() { + return this.input; + } + + public List getPage() { + return this.page; + } + + /** + * Creates a sub list of the given list by creating defining start and end from the requested page of the form + * + * @param list + * the list to paginate + * @param pageSize + * The number of items to return in each page + * @param page + * the page to return - start index is 1 + * + * @return a {@link Paging} instance from which the selected page (list) can be retrieved + */ + public static Paging asPage(List list, int pageSize, int page) { + + Paging paging = new Paging<>(pageSize, page); + paging.nrOfElements = list.size(); + + if (paging.pageSize <= 0 || paging.pageToReturn <= 0) { + paging.nrOfPages = 0; + paging.pageSize = list.size(); + paging.pageToReturn = 0; + paging.input = list; + paging.page = list; + return paging; + } + + int size = list.size(); + + // calculate maximum number of pages + paging.nrOfPages = size / paging.pageSize; + if (size % paging.pageSize != 0) + paging.nrOfPages++; + + // and from this validate requested page + paging.pageToReturn = Math.min(paging.pageToReturn, paging.nrOfPages); + + // now we can calculate the start and end of the page + int start = Math.max(0, paging.pageSize * paging.pageToReturn - paging.pageSize); + int end = Math.min(size, paging.pageSize * paging.pageToReturn); + + // and return the list + paging.page = list.subList(start, end); + + // fix page size + if (paging.page.size() < paging.pageSize) + paging.pageSize = paging.page.size(); + + return paging; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/Tuple.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/Tuple.java new file mode 100644 index 000000000..e7ec21dba --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/Tuple.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +/** + * Simple wrapper for two elements + * + * @author Robert von Burg + */ +public class Tuple { + + private Object first; + private Object second; + + public Tuple() { + // + } + + public Tuple(T first, U second) { + this.first = first; + this.second = second; + } + + @SuppressWarnings("unchecked") + public T getFirst() { + return (T) this.first; + } + + public void setFirst(T first) { + this.first = first; + } + + @SuppressWarnings("unchecked") + public U getSecond() { + return (U) this.second; + } + + public void setSecond(U second) { + this.second = second; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/dbc/DBC.java b/li.strolch.utils/src/main/java/li/strolch/utils/dbc/DBC.java new file mode 100644 index 000000000..6800f5fa1 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/dbc/DBC.java @@ -0,0 +1,166 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.dbc; + +import java.io.File; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collection; + +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +public enum DBC { + + PRE, INTERIM, POST; + + public void assertEquals(String msg, T value1, T value2) { + if (value1 == null && value2 == null) + return; + + if (value1 != null && value1.equals(value2)) + return; + + if (value2 != null && value2.equals(value1)) + return; + + String ex = "{0}: {1} != {2}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg, value1, value2); + throw new DbcException(ex); + } + + public void assertNotEquals(String msg, T value1, T value2) { + if (value1 != null && !value1.equals(value2)) + return; + + if (value2 != null && !value2.equals(value1)) + return; + + String ex = "{0}: {1} == {2}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg, value1, value2); + throw new DbcException(ex); + } + + public void assertTrue(String msg, boolean value) { + if (!value) { + String ex = "Expected true, but was false: {0}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertFalse(String msg, boolean value) { + if (value) { + String ex = "Expected false, but was true: {0}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertEmpty(String msg, String value) { + if (!StringHelper.isEmpty(value)) { + String ex = "{0}: Illegal non-empty value: {1}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg, value); + throw new DbcException(ex); + } + } + + public void assertEmpty(String msg, Object[] array) { + assertNotNull(msg, array); + if (array.length != 0) { + String ex = "{0}: Illegal non-empty value: {1}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg, Arrays.toString(array)); + throw new DbcException(ex); + } + } + + public void assertEmpty(String msg, Collection collection) { + assertNotNull(msg, collection); + if (!collection.isEmpty()) { + String ex = "{0}: Illegal non-empty value: {1}"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg, collection.toString()); + throw new DbcException(ex); + } + } + + public void assertNotEmpty(String msg, String value) { + if (StringHelper.isEmpty(value)) { + String ex = "{0}: Illegal empty value"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertNotEmpty(String msg, Object[] array) { + assertNotNull(msg, array); + if (array.length == 0) { + String ex = "{0}: Illegal empty value"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertNotEmpty(String msg, Collection collection) { + assertNotNull(msg, collection); + if (collection.isEmpty()) { + String ex = "{0}: Illegal empty value"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertNotNull(String msg, Object value) { + if (value == null) { + String ex = "{0}: Illegal null value"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertNull(String msg, Object value) { + if (value != null) { + String ex = "{0}: {1} != null"; //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg, value); + throw new DbcException(ex); + } + } + + public void assertNotExists(String msg, File file) { + if (file.exists()) { + String ex = MessageFormat.format("Illegal situation as file ({0}) exists: {1}", file, msg); //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public void assertExists(String msg, File file) { + if (!file.exists()) { + String ex = MessageFormat.format("Illegal situation as file ({0}) does not exist: {1}", file, msg); //$NON-NLS-1$ + ex = MessageFormat.format(ex, msg); + throw new DbcException(ex); + } + } + + public class DbcException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public DbcException(String message) { + super(message); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/exceptions/XmlException.java b/li.strolch.utils/src/main/java/li/strolch/utils/exceptions/XmlException.java new file mode 100644 index 000000000..0f48939df --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/exceptions/XmlException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.exceptions; + +/** + * @author Robert von Burg + */ +public class XmlException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * @param message + */ + public XmlException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public XmlException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/AesCryptoHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/AesCryptoHelper.java new file mode 100644 index 000000000..e63a26a82 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/AesCryptoHelper.java @@ -0,0 +1,351 @@ +package li.strolch.utils.helper; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.security.AlgorithmParameters; +import java.security.spec.KeySpec; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.dbc.DBC; + +public class AesCryptoHelper { + + private static final String CIPHER = "AES/CBC/PKCS5Padding"; + + private static final Logger logger = LoggerFactory.getLogger(AesCryptoHelper.class); + + public static OutputStream wrapEncrypt(char[] password, byte[] salt, OutputStream outputStream) { + + try { + + // set up key + SecretKey secret = buildSecret(password, salt); + + return wrapEncrypt(secret, outputStream); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static OutputStream wrapEncrypt(SecretKey secret, OutputStream outputStream) { + + try { + + // set up cipher + Cipher cipher = Cipher.getInstance(CIPHER); + cipher.init(Cipher.ENCRYPT_MODE, secret); + + // set up the initialization vector + AlgorithmParameters params = cipher.getParameters(); + byte[] initVector = params.getParameterSpec(IvParameterSpec.class).getIV(); + DBC.INTERIM.assertEquals("IV must be 16 bytes long!", 16, initVector.length); + + // write the initialization vector, but not through the cipher output stream! + outputStream.write(initVector); + outputStream.flush(); + + CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); + return cipherOutputStream; + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static InputStream wrapDecrypt(char[] password, byte[] salt, InputStream inputStream) { + + try { + + // set up key + SecretKey secret = buildSecret(password, salt); + + return wrapDecrypt(secret, inputStream); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static InputStream wrapDecrypt(SecretKey secret, InputStream inputStream) { + + try { + + // read the initialization vector from the normal input stream + byte[] initVector = new byte[16]; + inputStream.read(initVector); + + // init cipher + Cipher cipher = Cipher.getInstance(CIPHER); + cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initVector)); + + CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher); + return cipherInputStream; + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void encrypt(char[] password, byte[] salt, String clearTextFileS, String encryptedFileS) { + + try (FileInputStream inFile = new FileInputStream(clearTextFileS); + FileOutputStream outFile = new FileOutputStream(encryptedFileS)) { + + encrypt(password, salt, inFile, outFile); + + } catch (Exception e) { + throw new RuntimeException("Failed to encrypt file " + clearTextFileS + " to " + encryptedFileS, e); + } + + logger.info("Encrypted file " + clearTextFileS + " to " + encryptedFileS); + } + + public static void encrypt(SecretKey secret, String clearTextFileS, String encryptedFileS) { + + try (FileInputStream inFile = new FileInputStream(clearTextFileS); + FileOutputStream outFile = new FileOutputStream(encryptedFileS)) { + + encrypt(secret, inFile, outFile); + + } catch (Exception e) { + throw new RuntimeException("Failed to encrypt file " + clearTextFileS + " to " + encryptedFileS, e); + } + + logger.info("Encrypted file " + clearTextFileS + " to " + encryptedFileS); + } + + public static void encrypt(char[] password, byte[] salt, InputStream inFile, OutputStream outFile) { + + try { + + // set up key + SecretKey secret = buildSecret(password, salt); + + encrypt(secret, inFile, outFile); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void encrypt(SecretKey secret, InputStream inFile, OutputStream outFile) { + + try { + + // set up cipher + Cipher cipher = Cipher.getInstance(CIPHER); + cipher.init(Cipher.ENCRYPT_MODE, secret); + + // set up the initialization vector + AlgorithmParameters params = cipher.getParameters(); + byte[] initVector = params.getParameterSpec(IvParameterSpec.class).getIV(); + DBC.INTERIM.assertEquals("IV must be 16 bytes long!", 16, initVector.length); + outFile.write(initVector); + + byte[] input = new byte[64]; + int bytesRead; + + while ((bytesRead = inFile.read(input)) != -1) { + byte[] output = cipher.update(input, 0, bytesRead); + if (output != null) + outFile.write(output); + } + + byte[] output = cipher.doFinal(); + if (output != null) + outFile.write(output); + + outFile.flush(); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void decrypt(char[] password, byte[] salt, String encryptedFileS, String decryptedFileS) { + + try (FileInputStream fis = new FileInputStream(encryptedFileS); + FileOutputStream fos = new FileOutputStream(decryptedFileS)) { + + decrypt(password, salt, fis, fos); + + } catch (Exception e) { + throw new RuntimeException("Failed to decrypt file " + decryptedFileS + " to " + decryptedFileS, e); + } + + logger.info("Decrypted file " + encryptedFileS + " to " + decryptedFileS); + + } + + public static void decrypt(SecretKey secret, String encryptedFileS, String decryptedFileS) { + + try (FileInputStream fis = new FileInputStream(encryptedFileS); + FileOutputStream fos = new FileOutputStream(decryptedFileS)) { + + decrypt(secret, fis, fos); + + } catch (Exception e) { + throw new RuntimeException("Failed to decrypt file " + decryptedFileS + " to " + decryptedFileS, e); + } + + logger.info("Decrypted file " + encryptedFileS + " to " + decryptedFileS); + + } + + public static void decrypt(char[] password, byte[] salt, InputStream fis, OutputStream fos) { + + try { + + // set up key + SecretKey secret = buildSecret(password, salt); + + decrypt(secret, fis, fos); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void decrypt(SecretKey secret, InputStream fis, OutputStream fos) { + + try { + + // read the initialization vector + byte[] initVector = new byte[16]; + fis.read(initVector); + + // init cipher + Cipher cipher = Cipher.getInstance(CIPHER); + cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initVector)); + + byte[] in = new byte[64]; + int read; + while ((read = fis.read(in)) != -1) { + byte[] output = cipher.update(in, 0, read); + if (output != null) + fos.write(output); + } + + byte[] output = cipher.doFinal(); + if (output != null) + fos.write(output); + + fos.flush(); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static byte[] encrypt(char[] password, byte[] salt, String clearText) { + return encrypt(password, salt, clearText.getBytes()); + } + + public static byte[] encrypt(SecretKey secret, byte[] salt, String clearText) { + return encrypt(secret, clearText.getBytes()); + } + + public static byte[] encrypt(char[] password, byte[] salt, byte[] clearTextBytes) { + + try { + + // set up key + SecretKey secret = buildSecret(password, salt); + + return encrypt(secret, clearTextBytes); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static byte[] encrypt(SecretKey secret, byte[] clearTextBytes) { + + try { + + // set up cipher + Cipher cipher = Cipher.getInstance(CIPHER); + cipher.init(Cipher.ENCRYPT_MODE, secret); + + // set up the initialization vector + AlgorithmParameters params = cipher.getParameters(); + byte[] initVector = params.getParameterSpec(IvParameterSpec.class).getIV(); + DBC.INTERIM.assertEquals("IV must be 16 bytes long!", 16, initVector.length); + + // encrypt + byte[] encryptedBytes = cipher.doFinal(clearTextBytes); + + // create result bytes + ByteBuffer byteBuffer = ByteBuffer.allocate(initVector.length + encryptedBytes.length); + byteBuffer.put(initVector); + byteBuffer.put(encryptedBytes); + + return byteBuffer.array(); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static byte[] decrypt(char[] password, byte[] salt, byte[] encryptedBytes) { + + try { + + // set up key + SecretKey secret = buildSecret(password, salt); + + return decrypt(secret, encryptedBytes); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static byte[] decrypt(SecretKey secret, byte[] encryptedBytes) { + + try { + + // read initialization vector + byte[] initVector = new byte[16]; + System.arraycopy(encryptedBytes, 0, initVector, 0, 16); + + // init cipher + Cipher cipher = Cipher.getInstance(CIPHER); + cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initVector)); + + byte[] decryptedBytes = cipher.doFinal(encryptedBytes, 16, encryptedBytes.length - 16); + return decryptedBytes; + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static SecretKey buildSecret(char[] password, byte[] salt) { + try { + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + KeySpec keySpec = new PBEKeySpec(password, salt, 65536, 256); + SecretKey secretKey = factory.generateSecret(keySpec); + SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); + + return secret; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/ArraysHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ArraysHelper.java new file mode 100644 index 000000000..fd32e29e7 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ArraysHelper.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.util.Arrays; + +/** + * @author Robert von Burg + */ +public class ArraysHelper { + + /** + * Returns true if the byte array contains the given byte value + * + * @param bytes + * the array to search in + * @param searchByte + * the value to search for + * + * @return true if found, false if not + */ + public static boolean contains(byte[] bytes, byte searchByte) { + for (byte b : bytes) { + if (b == searchByte) + return true; + } + return false; + } + + /** + * Creates a simple copy of the given array + * + * @param bytes + * the array to copy + * + * @return the copy + */ + public static byte[] copyOf(byte[] bytes) { + return Arrays.copyOf(bytes, bytes.length); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/AsciiHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/AsciiHelper.java new file mode 100644 index 000000000..ce6b3ff45 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/AsciiHelper.java @@ -0,0 +1,322 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +/** + * ASCII constants + * + * @author Robert von Burg + */ +public class AsciiHelper { + + /** + * ASCII Value 0, interpretation: NUL
+ * Description: Null character + */ + public static final char NUL = (char) 0; // Null character + + /** + * ASCII Value 1, interpretation: SOH
+ * Description: Start of Header + */ + public static final char SOH = (char) 1; // Start of Header + + /** + * ASCII Value 2, interpretation: STX
+ * Description: Start of Text + */ + public static final char STX = (char) 2; // Start of Text + + /** + * ASCII Value 3, interpretation: ETX
+ * Description: End of Text + */ + public static final char ETX = (char) 3; // End of Text + + /** + * ASCII Value 4, interpretation: EOT
+ * Description: End of Transmission + */ + public static final char EOT = (char) 4; // End of Transmission + + /** + * ASCII Value 5, interpretation: ENQ
+ * Description: Enquiry + */ + public static final char ENQ = (char) 5; // Enquiry + + /** + * ASCII Value 6, interpretation: ACK
+ * Description: Acknowledgement + */ + public static final char ACK = (char) 6; // Acknowledgement + + /** + * ASCII Value 7, interpretation: BEL
+ * Description: Bell + */ + public static final char BEL = (char) 7; // Bell + + /** + * ASCII Value 8, interpretation: BS
+ * Description: Backspace + */ + public static final char BS = (char) 8; // Backspace + + /** + * ASCII Value 9, interpretation: HT
+ * Description: Horizontal Tab + */ + public static final char HT = (char) 9; // Horizontal Tab + + /** + * ASCII Value 10, interpretation: LF
+ * Description: Line Feed + */ + public static final char LF = (char) 10; // Line Feed + + /** + * ASCII Value 11, interpretation: VT
+ * Description: Vertical Tab + */ + public static final char VT = (char) 11; // Vertical Tab + + /** + * ASCII Value 12, interpretation: FF
+ * Description: Form Feed + */ + public static final char FF = (char) 12; // Form Feed + + /** + * ASCII Value 13, interpretation: CR
+ * Description: Carriage Return + */ + public static final char CR = (char) 13; // Carriage Return + + /** + * ASCII Value 14, interpretation: SO
+ * Description: Shift Out + */ + public static final char SO = (char) 14; // Shift Out + + /** + * ASCII Value 15, interpretation: SI
+ * Description: Shift In + */ + public static final char SI = (char) 15; // Shift In + + /** + * ASCII Value 16, interpretation: DLE
+ * Description: Data Link Escape + */ + public static final char DLE = (char) 16; // Data Link Escape + + /** + * ASCII Value 17, interpretation: DC1
+ * Description: (XON) Device Control 1 + */ + public static final char DC1 = (char) 17; // (XON) Device Control 1 + + /** + * ASCII Value 18, interpretation: DC2
+ * Description: Device Control 2 + */ + public static final char DC2 = (char) 18; // Device Control 2 + + /** + * ASCII Value 19 interpretation: DC3
+ * Description: (XOFF) Device Control 3 + */ + public static final char DC3 = (char) 19; // (XOFF) Device Control 3 + + /** + * ASCII Value 20, interpretation: DC4
+ * Description: Device Control 4 + */ + public static final char DC4 = (char) 20; // Device Control 4 + + /** + * ASCII Value 21, interpretation: NAK
+ * Description: Negative Acknowledgment + */ + public static final char NAK = (char) 21; // Negative Acknowledgment + + /** + * ASCII Value 22, interpretation: SYN
+ * Description: Synchronous Idle + */ + public static final char SYN = (char) 22; // Synchronous Idle + + /** + * ASCII Value 23, interpretation: ETB
+ * Description: End of Transmission Block + */ + public static final char ETB = (char) 23; // End of Transmission Block + + /** + * ASCII Value 24, interpretation: CAN
+ * Description: Cancel + */ + public static final char CAN = (char) 24; // Cancel + + /** + * ASCII Value 25, interpretation: EM
+ * Description: End of Medium + */ + public static final char EM = (char) 25; // End of Medium + + /** + * ASCII Value 26, interpretation: SUB
+ * Description: Substitute + */ + public static final char SUB = (char) 26; // Substitute + + /** + * ASCII Value 27, interpretation: ESC
+ * Description: Escape + */ + public static final char ESC = (char) 27; // Escape + + /** + * ASCII Value 28, interpretation: FS
+ * Description: File Separator + */ + public static final char FS = (char) 28; // File Separator + + /** + * ASCII Value 29, interpretation: GS
+ * Description: Group Separator + */ + public static final char GS = (char) 29; // Group Separator + + /** + * ASCII Value 30, interpretation: RS
+ * Description: Request to Send (Record Separator) + */ + public static final char RS = (char) 30; // Request to Send (Record Separator) + + /** + * ASCII Value 31, interpretation: US
+ * Description: Unit Separator + */ + public static final char US = (char) 31; // Unit Separator + + /** + * ASCII Value 32, interpretation: SP
+ * Description: Space + */ + public static final char SP = (char) 32; // Space + + /** + * ASCII Value 127, interpretation: DEL
+ * Description: Delete + */ + public static final char DEL = (char) 127; // Delete + + /** + * Returns the ASCII Text of a certain bye value + * + * @param b + * @return String + */ + public static String getAsciiText(byte b) { + return getAsciiText((char) b); + } + + /** + * Returns the ASCII Text of a certain char value + * + * @param c + * @return String + */ + @SuppressWarnings("nls") + public static String getAsciiText(char c) { + // else if(c == ) { return "";} + if (c == NUL) { + return "NUL"; + } else if (c == SOH) { + return "SOH"; + } else if (c == STX) { + return "STX"; + } else if (c == ETX) { + return "ETX"; + } else if (c == EOT) { + return "EOT"; + } else if (c == ENQ) { + return "ENQ"; + } else if (c == ACK) { + return "ACK"; + } else if (c == BEL) { + return "BEL"; + } else if (c == BS) { + return "BS"; + } else if (c == HT) { + return "HT"; + } else if (c == LF) { + return "LF"; + } else if (c == VT) { + return "VT"; + } else if (c == FF) { + return "FF"; + } else if (c == CR) { + return "CR"; + } else if (c == SO) { + return "SO"; + } else if (c == SI) { + return "SI"; + } else if (c == DLE) { + return "DLE"; + } else if (c == DC1) { + return "DC1"; + } else if (c == DC2) { + return "DC2"; + } else if (c == DC3) { + return "DC3"; + } else if (c == DC4) { + return "DC4"; + } else if (c == NAK) { + return "NAK"; + } else if (c == SYN) { + return "SYN"; + } else if (c == ETB) { + return "ETB"; + } else if (c == CAN) { + return "CAN"; + } else if (c == EM) { + return "EM"; + } else if (c == SUB) { + return "SUB"; + } else if (c == ESC) { + return "ESC"; + } else if (c == FS) { + return "FS"; + } else if (c == GS) { + return "GS"; + } else if (c == RS) { + return "RS"; + } else if (c == US) { + return "US"; + } else if (c == SP) { + return "SP"; + } else if (c == DEL) { + return "DEL"; + } else if ((c) > 32 && (c) < 127) { + return String.valueOf(c); + } else { + return "(null:" + (byte) c + ")"; + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/BaseEncoding.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/BaseEncoding.java new file mode 100644 index 000000000..4bb9849d7 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/BaseEncoding.java @@ -0,0 +1,1008 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.text.MessageFormat; + +/** + *

+ * This class implements the encoding and decoding of RFC 4648 https://tools.ietf.org/html/rfc4648. + *

+ * + *

+ * The following implementations are supported: + *

    + *
  • Base64
  • + *
  • Base64 URL safe
  • + *
  • Base32
  • + *
  • Base32 HEX
  • + *
  • Base16 / HEX
  • + *
+ *

+ * + *

+ * As a further bonus, it is possible to use the algorithm with a client specified alphabet. In this case the client is + * responsible for generating the alphabet for use in the decoding + *

+ * + *

+ * This class also implements a number of utility methods to check if given data is in a valid encoding + *

+ * + * @author Robert von Burg + */ +public class BaseEncoding { + + // private static final Logger logger = LoggerFactory.getLogger(BaseEncoding.class); + + private static final int PADDING_64 = 2; + private static final int PADDING_32 = 6; + + public static final byte PAD = '='; + + static final byte[] BASE_16 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + static final byte[] BASE_32 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7' }; + + static final byte[] BASE_32_HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V' }; + + static final byte[] BASE_32_DMEDIA = { '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y' }; + + static final byte[] BASE_32_CROCKFORD = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z' }; + + static final byte[] BASE_64 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '+', '/' }; + + static final byte[] BASE_64_SAFE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', + '5', '6', '7', '8', '9', '-', '_' }; + + // these reverse base encoding alphabets were generated from the actual alphabet + + static final byte[] REV_BASE_16 = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + static final byte[] REV_BASE_32 = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + static final byte[] REV_BASE_32_CROCKFORD = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, + -1, 18, 19, -1, 20, 21, -1, 22, 23, 24, 25, 26, -1, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1 }; + + static final byte[] REV_BASE_32_DMEDIA = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + static final byte[] REV_BASE_32_HEX = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + static final byte[] REV_BASE_64 = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, + 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 }; + + static final byte[] REV_BASE_64_SAFE = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 }; + + public static byte[] toBase64(byte[] bytes) { + return toBase64(BASE_64, bytes); + } + + public static String toBase64(String data) { + return toBase64(BASE_64, data); + } + + public static byte[] toBase64Safe(byte[] bytes) { + return toBase64(BASE_64_SAFE, bytes); + } + + public static String toBase64Safe(String data) { + return toBase64(BASE_64_SAFE, data); + } + + public static String toBase64(byte[] alphabet, String data) { + return new String(toBase64(alphabet, data.getBytes())); + } + + public static byte[] toBase32(byte[] bytes) { + return toBase32(BASE_32, bytes); + } + + public static String toBase32(String data) { + return toBase32(BASE_32, data); + } + + public static byte[] toBase32Hex(byte[] bytes) { + return toBase32(BASE_32_HEX, bytes); + } + + public static String toBase32Hex(String data) { + return toBase32(BASE_32_HEX, data); + } + + public static byte[] toBase32Dmedia(byte[] bytes) { + return toBase32(BASE_32_DMEDIA, bytes); + } + + public static String toBase32Dmedia(String data) { + return toBase32(BASE_32_DMEDIA, data); + } + + public static byte[] toBase32Crockford(byte[] bytes) { + return toBase32(BASE_32_CROCKFORD, bytes); + } + + public static String toBase32Crockford(String data) { + return toBase32(BASE_32_CROCKFORD, data); + } + + public static String toBase32(byte[] alphabet, String data) { + return new String(toBase32(alphabet, data.getBytes())); + } + + public static byte[] toBase16(byte[] bytes) { + return toBase16(BASE_16, bytes); + } + + public static String toBase16(String data) { + return toBase16(BASE_16, data); + } + + public static String toBase16(byte[] alphabet, String data) { + return new String(toBase16(alphabet, data.getBytes())); + } + + public static byte[] fromBase64(byte[] bytes) { + return fromBase64(REV_BASE_64, bytes); + } + + public static String fromBase64(String data) { + return fromBase64(REV_BASE_64, data); + } + + public static String fromBase64Safe(String data) { + return fromBase64(REV_BASE_64_SAFE, data); + } + + public static String fromBase64(byte[] alphabet, String data) { + return new String(fromBase64(alphabet, data.getBytes())); + } + + public static byte[] fromBase32(byte[] bytes) { + return fromBase32(REV_BASE_32, bytes); + } + + public static String fromBase32(String data) { + return fromBase32(REV_BASE_32, data); + } + + public static byte[] fromBase32Hex(byte[] bytes) { + return fromBase32(REV_BASE_32_HEX, bytes); + } + + public static String fromBase32Hex(String data) { + return fromBase32(REV_BASE_32_HEX, data); + } + + public static byte[] fromBase32Dmedia(byte[] bytes) { + return fromBase32(REV_BASE_32_DMEDIA, bytes); + } + + public static String fromBase32Dmedia(String data) { + return fromBase32(REV_BASE_32_DMEDIA, data); + } + + public static byte[] fromBase32Crockford(byte[] bytes) { + return fromBase32(REV_BASE_32_CROCKFORD, bytes); + } + + public static String fromBase32Crockford(String data) { + return fromBase32(REV_BASE_32_CROCKFORD, data); + } + + public static String fromBase32(byte[] alphabet, String data) { + return new String(fromBase32(alphabet, data.getBytes())); + } + + public static byte[] fromBase16(byte[] bytes) { + return fromBase16(REV_BASE_16, bytes); + } + + public static String fromBase16(String data) { + return fromBase16(REV_BASE_16, data); + } + + public static String fromBase16(byte[] alphabet, String data) { + return new String(fromBase16(alphabet, data.getBytes())); + } + + public static boolean isBase64(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_64, bytes, PADDING_64); + } + + public static boolean isBase64(String data) { + return isEncodedByAlphabet(REV_BASE_64, data, PADDING_64); + } + + public static boolean isBase64Safe(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_64_SAFE, bytes, PADDING_64); + } + + public static boolean isBase64Safe(String data) { + return isEncodedByAlphabet(REV_BASE_64_SAFE, data, PADDING_64); + } + + public static boolean isBase32(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_32, bytes, PADDING_32); + } + + public static boolean isBase32(String data) { + return isEncodedByAlphabet(REV_BASE_32, data, PADDING_32); + } + + public static boolean isBase32Hex(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_32_HEX, bytes, PADDING_32); + } + + public static boolean isBase32Hex(String data) { + return isEncodedByAlphabet(REV_BASE_32_HEX, data, PADDING_32); + } + + public static boolean isBase32Crockford(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_32_CROCKFORD, bytes, PADDING_32); + } + + public static boolean isBase32Crockford(String data) { + return isEncodedByAlphabet(REV_BASE_32_CROCKFORD, data, PADDING_32); + } + + public static boolean isBase32Dmedia(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_32_DMEDIA, bytes, PADDING_32); + } + + public static boolean isBase32Dmedia(String data) { + return isEncodedByAlphabet(REV_BASE_32_DMEDIA, data, PADDING_32); + } + + public static boolean isBase16(byte[] bytes) { + return isEncodedByAlphabet(REV_BASE_16, bytes, 0); + } + + public static boolean isBase16(String data) { + return isEncodedByAlphabet(REV_BASE_16, data, 0); + } + + public static boolean isEncodedByAlphabet(byte[] alphabet, String data, int padding) { + return isEncodedByAlphabet(alphabet, data.getBytes(), padding); + } + + /** + * @param alphabet + * @param bytes + * @param maxPadding + * + * @return + */ + public static boolean isEncodedByAlphabet(byte[] alphabet, byte[] bytes, int maxPadding) { + if (bytes.length == 0) + return true; + + int paddingStart = 0; + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + if (b < 0 || b > alphabet.length) + return false; + + byte c = alphabet[b]; + if (c == -1) { + + if (b == PAD && maxPadding != 0) { + if (paddingStart == 0) + paddingStart = i; + + continue; + } + + return false; + } + } + + if (paddingStart != 0 && paddingStart < (bytes.length - maxPadding)) + return false; + + return true; + } + + /** + * Encodes the given data to a 64-bit alphabet encoding. Thus the passed alphabet can be any arbitrary alphabet + * + * @param alphabet + * the 64-bit alphabet to use + * @param bytes + * the bytes to encode + * + * @return the encoded data + */ + public static byte[] toBase64(byte[] alphabet, byte[] bytes) { + if (bytes.length == 0) + return new byte[0]; + if (alphabet.length != 64) { + String msg = MessageFormat.format("Alphabet does not have expected size 64 but is {0}", alphabet.length); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + // 6 bits input for every 8 bits (1 byte) output + // least common multiple of 6 bits input and 8 bits output = 24 + // and output multiple is then lcm(6, 8) / 6 = 4 + // thus we need to write multiples of 4 bytes of data + int bitsIn = 6; + int outputMultiple = 4; + + // first convert to bits + int nrOfInputBytes = bytes.length; + int nrOfInputBits = nrOfInputBytes * Byte.SIZE; + + // calculate number of bits missing for multiples of bitsIn + int inputPadding = nrOfInputBits % bitsIn; + int nrOfOutputBytes; + if (inputPadding == 0) + nrOfOutputBytes = nrOfInputBits / bitsIn; + else + nrOfOutputBytes = (nrOfInputBits + (bitsIn - (inputPadding))) / bitsIn; + + // calculate number of bits missing for multiple of bitsOut + int nrOfBytesPadding = outputMultiple - (nrOfOutputBytes % outputMultiple); + if (nrOfBytesPadding == outputMultiple) + nrOfBytesPadding = 0; + + // actual result array is multiples of bitsOut/8 thus sum of: + int txtLength = nrOfOutputBytes + nrOfBytesPadding; + +// logger.info(String.format("Input: %d bytes, Output: %d bytes, Padding: %d bytes, TextLength: %d", +// nrOfInputBytes, nrOfOutputBytes, nrOfBytesPadding, txtLength)); + + byte[] txt = new byte[txtLength]; + long bits; + int bytesPos = 0; + int txtPos = 0; + while (bytesPos < bytes.length) { + + int remaining = bytes.length - bytesPos; + // get up to 24 bits of data in 3 bytes + bits = 0; + if (remaining >= 3) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 16) // + | ((long) (bytes[bytesPos++] & 0xff) << 8) // + | ((bytes[bytesPos++] & 0xff)); + + } else if (remaining == 2) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 16) // + | ((long) (bytes[bytesPos++] & 0xff) << 8); + + } else if (remaining == 1) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 16); + } + + // always start at 24. bit + int bitPos = 23; + + // always write 24 bits (6 bits * 4), but this will also write into the padding + // we will fix this by writing the padding as has been calculated previously + while (bitPos >= 0) { + + int index = 0; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 32; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 16; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 8; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 4; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 2; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 1; + bitPos--; + byte character = alphabet[index]; + txt[txtPos] = character; + txtPos++; + } + } + + // write any padding that was calculated + if (nrOfBytesPadding != 0) { + int paddingPos = txtPos - nrOfBytesPadding; + for (; paddingPos < txtLength; paddingPos++) { + txt[paddingPos] = PAD; + } + } + + return txt; + } + + /** + * Encodes the given data to a 32-bit alphabet encoding. Thus the passed alphabet can be any arbitrary alphabet + * + * @param alphabet + * the 32-bit alphabet to use + * @param bytes + * the bytes to encode + * + * @return the encoded data + */ + public static byte[] toBase32(byte[] alphabet, byte[] bytes) { + if (bytes.length == 0) + return new byte[0]; + if (alphabet.length != 32) { + String msg = MessageFormat.format("Alphabet does not have expected size 32 but is {0}", alphabet.length); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + // 5 bits input for every 8 bits (1 byte) output + // least common multiple of 5 bits input and 8 bits output = 40 + // and output multiple is then lcm(5, 8) / 5 = 8 + // thus we need to write multiples of 8 bytes of data + int bitsIn = 5; + int outputMultiple = 8; + + // first convert to bits + int nrOfInputBytes = bytes.length; + int nrOfInputBits = nrOfInputBytes * Byte.SIZE; + + // calculate number of bits missing for multiples of bitsIn + int inputPadding = nrOfInputBits % bitsIn; + int nrOfOutputBytes; + if (inputPadding == 0) + nrOfOutputBytes = nrOfInputBits / bitsIn; + else + nrOfOutputBytes = (nrOfInputBits + (bitsIn - (inputPadding))) / bitsIn; + + // calculate number of bits missing for multiple of bitsOut + int nrOfBytesPadding = outputMultiple - (nrOfOutputBytes % outputMultiple); + if (nrOfBytesPadding == outputMultiple) + nrOfBytesPadding = 0; + + // actual result array is multiples of bitsOut/8 thus sum of: + int txtLength = nrOfOutputBytes + nrOfBytesPadding; + +// logger.info(String.format("Input: %d bytes, Output: %d bytes, Padding: %d bytes, TextLength: %d", +// nrOfInputBytes, nrOfOutputBytes, nrOfBytesPadding, txtLength)); + + byte[] txt = new byte[txtLength]; + long bits; + int bytesPos = 0; + int txtPos = 0; + while (bytesPos < bytes.length) { + + int remaining = bytes.length - bytesPos; + // get up to 40 bits of data in 5 bytes + bits = 0; + if (remaining >= 5) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 32) // + | ((long) (bytes[bytesPos++] & 0xff) << 24) // + | ((long) (bytes[bytesPos++] & 0xff) << 16) // + | ((long) (bytes[bytesPos++] & 0xff) << 8) // + | ((bytes[bytesPos++] & 0xff)); + + } else if (remaining == 4) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 32) // + | ((long) (bytes[bytesPos++] & 0xff) << 24) // + | ((long) (bytes[bytesPos++] & 0xff) << 16) // + | ((long) (bytes[bytesPos++] & 0xff) << 8); + + } else if (remaining == 3) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 32) // + | ((long) (bytes[bytesPos++] & 0xff) << 24) // + | ((long) (bytes[bytesPos++] & 0xff) << 16); + + } else if (remaining == 2) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 32) // + | ((long) (bytes[bytesPos++] & 0xff) << 24); + + } else if (remaining == 1) { + + bits = ((long) (bytes[bytesPos++] & 0xff) << 32); + + } + + // always start at 40. bit + int bitPos = 39; + + // always write 40 bits (5 bytes * 8 multiples), but this will also write into the padding + // we will fix this by writing the padding as has been calculated previously + while (bitPos >= 0) { + + int index = 0; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 16; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 8; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 4; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 2; + bitPos--; + index |= ((bits >>> bitPos) & 1) == 0 ? 0 : 1; + bitPos--; + byte character = alphabet[index]; + txt[txtPos] = character; + txtPos++; + } + } + + // write any padding that was calculated + if (nrOfBytesPadding != 0) { + int paddingPos = txtPos - nrOfBytesPadding; + for (; paddingPos < txtLength; paddingPos++) { + txt[paddingPos] = PAD; + } + } + + return txt; + } + + /** + * Encodes the given data to a 16-bit alphabet encoding. Thus the passed alphabet can be any arbitrary alphabet + * + * @param alphabet + * the 16-bit alphabet to use + * @param bytes + * the bytes to encode + * + * @return the encoded data + */ + public static byte[] toBase16(byte[] alphabet, byte[] bytes) { + if (bytes.length == 0) + return new byte[0]; + if (alphabet.length != 16) { + String msg = MessageFormat.format("Alphabet does not have expected size 16 but is {0}", alphabet.length); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + // calculate output text length + int nrOfInputBytes = bytes.length; + int nrOfOutputBytes = nrOfInputBytes * 2; + int txtLength = nrOfOutputBytes; + +// logger.info(String.format("Input: %d bytes, Output: %d bytes, TextLength: %d", nrOfInputBytes, nrOfOutputBytes, +// txtLength)); + + byte[] txt = new byte[txtLength]; + byte bits; + int bytesPos = 0; + int txtPos = 0; + while (bytesPos < bytes.length) { + + // get 8 bits of data (1 byte) + bits = bytes[bytesPos++]; + + // now write the 8 bits as 2 * 4 bits + + // output byte 1 + int index = (bits >>> 4) & 0xf; + byte character = alphabet[index]; + txt[txtPos] = character; + txtPos++; + + // output byte 2 + index = bits & 0xf; + character = alphabet[index]; + txt[txtPos] = character; + txtPos++; + } + + return txt; + } + + /** + * Decodes the given Base64 encoded data to the original data set + * + * @param alphabet + * the 64-bit alphabet to use + * @param bytes + * the bytes to decode + * + * @return the decoded data + */ + public static byte[] fromBase64(byte[] alphabet, byte[] bytes) { + int inputLength = bytes.length; + if (inputLength == 0) + return new byte[0]; + if ((inputLength % 4) != 0) { + String msg = MessageFormat.format( + "The input bytes to be decoded must be multiples of 4, but is multiple of {0}", //$NON-NLS-1$ + (inputLength % 4)); + throw new RuntimeException(msg); + } + + if (alphabet.length != 128) { + String msg = MessageFormat.format("Alphabet does not have expected size 128 but is {0}", alphabet.length); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + if (!isEncodedByAlphabet(alphabet, bytes, PADDING_64)) + throw new RuntimeException("The data contains illegal values which are not mapped by the given alphabet!"); //$NON-NLS-1$ + + // find how much padding we have + int nrOfBytesPadding = 0; + if (bytes[inputLength - 1] == PAD) { + int end = inputLength - 1; + while (bytes[end] == PAD) + end--; + if (end != inputLength - 1) + nrOfBytesPadding = inputLength - 1 - end; + } + + int inputDataLength = inputLength - nrOfBytesPadding; + int dataLengthBits = inputDataLength * 6; // 6 bits data for every 8 bits inputs + // multiples of 6 required + // truncating is no problem due to the input having padding to have multiples of 32 bits + dataLengthBits = dataLengthBits - (dataLengthBits % 8); + int dataLengthBytes = dataLengthBits / 8; + + // f => Zg== + // fo => Zm8= + // foo => Zm9v + + // we want to write as much as 24 bits in multiples of 6. + // these multiples of 6 are read from multiples of 8 + // i.e. we discard 2 bits from every 8 bits input + // thus we need to read 24 / 6 = 4 bytes + + byte[] data = new byte[dataLengthBytes]; + int dataPos = 0; + + // but we simply ignore the padding + int bytesPos = 0; + while (bytesPos < inputDataLength) { + int remaining = inputDataLength - bytesPos; + + long bits; + if (remaining >= 4) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 63) << 18) // + | ((long) (alphabet[bytes[bytesPos++]] & 63) << 12) // + | ((long) (alphabet[bytes[bytesPos++]] & 63) << 6) // + | (alphabet[bytes[bytesPos++]] & 63); + + } else if (remaining == 3) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 63) << 18) // + | ((long) (alphabet[bytes[bytesPos++]] & 63) << 12) // + | ((long) (alphabet[bytes[bytesPos++]] & 63) << 6); + + } else if (remaining == 2) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 63) << 18) // + | ((long) (alphabet[bytes[bytesPos++]] & 63) << 12); +// +// long b; +// byte a; +// a = bytes[0]; +// logger.info("1 a: " + a + " " + ((char) a) + " - " + ByteHelper.asBinary(a) + " " + indexOf(a)); +// b = (byte) (alphabet[a] & 63); +// logger.info("1 b: " + b + " - " + ((char) b) + " - " + ByteHelper.asBinary(b)); +// a = bytes[1]; +// logger.info("2 a: " + a + " " + ((char) a) + " - " + ByteHelper.asBinary(a) + " " + indexOf(a)); +// b = (byte) (alphabet[a] & 63); +// logger.info("2 b: " + b + " - " + ((char) b) + " - " + ByteHelper.asBinary(b)); + + } else if (remaining == 1) { + + bits = ((alphabet[bytes[bytesPos++]] & 63) << 18); + + } else { + + bits = 0L; + } + + // we can truncate to 8 bits + int toWrite = remaining >= 4 ? 3 : remaining * 6 / 8; + // max is always 3 bytes data from 4 bytes input + +// logger.info("toWrite: " + toWrite + ", remaining: " + remaining); +// logger.info("bits: " + ByteHelper.asBinary(bits)); + + // always start at 24. bit + int bitPos = 23; + // always write 24 bits (8 bits * n bytes) + for (int i = 0; i < toWrite; i++) { + + byte value = 0; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 128; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 64; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 32; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 16; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 8; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 4; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 2; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 1; + bitPos--; + data[dataPos] = value; + dataPos++; + } + } + + return data; + } + + /** + * Decodes the given Base32 encoded data to the original data set + * + * @param alphabet + * the 32-bit alphabet to use + * @param bytes + * the bytes to decode + * + * @return the decoded data + */ + public static byte[] fromBase32(byte[] alphabet, byte[] bytes) { + int inputLength = bytes.length; + if (inputLength == 0) + return new byte[0]; + if ((inputLength % 8) != 0) { + String msg = "The input bytes to be decoded must be multiples of 8, but is multiple of {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, (inputLength % 8)); + throw new RuntimeException(msg); + } + + if (alphabet.length != 128) { + String msg = MessageFormat.format("Alphabet does not have expected size 128 but is {0}", alphabet.length); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + if (!isEncodedByAlphabet(alphabet, bytes, PADDING_32)) + throw new RuntimeException("The data contains illegal values which are not mapped by the given alphabet!"); //$NON-NLS-1$ + + // find how much padding we have + int nrOfBytesPadding = 0; + if (bytes[inputLength - 1] == PAD) { + int end = inputLength - 1; + while (bytes[end] == PAD) + end--; + if (end != inputLength - 1) + nrOfBytesPadding = inputLength - 1 - end; + } + + int inputDataLength = inputLength - nrOfBytesPadding; + int dataLengthBits = inputDataLength * 5; // 5 bits data for every 8 bits inputs + // multiples of 8 required + // truncating is no problem due to the input having padding to have multiples of 40 bits + dataLengthBits = dataLengthBits - (dataLengthBits % 8); + int dataLengthBytes = dataLengthBits / 8; + +// logger.info("Input " + inputLength + " bytes, InputData " + inputDataLength + " bytes, Padding: " +// + nrOfBytesPadding + " bytes, dataLength: " + dataLengthBits + " bits, dataLengthBytes: " +// + dataLengthBytes + " bytes"); +// logger.info(ByteHelper.asBinary(bytes)); + + // we want to write as much as 40 bits in multiples of 5. + // these multiples of 5 are read from multiples of 8 + // i.e. we discard 3 bits from every 8 bits input + // thus we need to read 40 / 5 = 8 bytes + + byte[] data = new byte[dataLengthBytes]; + int dataPos = 0; + + // but we simply ignore the padding + int bytesPos = 0; + while (bytesPos < inputDataLength) { + int remaining = inputDataLength - bytesPos; + + long bits; + if (remaining >= 8) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 25) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 20) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 15) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 10) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 5) // + | (alphabet[bytes[bytesPos++]] & 31); + + } else if (remaining >= 7) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 25) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 20) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 15) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 10) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 5); + + } else if (remaining == 6) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 25) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 20) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 15) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 10); + + } else if (remaining == 5) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 25) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 20) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 15); + + } else if (remaining == 4) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 25) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 20); + + } else if (remaining == 3) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 25); + + } else if (remaining == 2) { + + bits = ((long) (alphabet[bytes[bytesPos++]] & 31) << 35) // + | ((long) (alphabet[bytes[bytesPos++]] & 31) << 30); + + } else if (remaining == 1) { + + bits = ((alphabet[bytes[bytesPos++]] & 31) << 35); + + } else { + + bits = 0L; + } + + // we can truncate to 8 bits + int toRead = remaining >= 8 ? 5 : remaining * 5 / 8; + // max is always 5 bytes data from 8 bytes input + + // always start at 40. bit + int bitPos = 39; + // always write 40 bits (5 bytes * 8 bits) + for (int i = 0; i < toRead; i++) { + + byte value = 0; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 128; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 64; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 32; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 16; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 8; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 4; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 2; + bitPos--; + value |= ((bits >>> bitPos) & 1) == 0 ? 0 : 1; + bitPos--; + data[dataPos] = value; + dataPos++; + } + } + + return data; + } + + /** + * Decodes the given Base16 encoded data to the original data set + * + * @param alphabet + * the 16-bit alphabet to use + * @param bytes + * the bytes to decode + * + * @return the decoded data + */ + public static byte[] fromBase16(byte[] alphabet, byte[] bytes) { + if (bytes.length == 0) + return new byte[0]; + if ((bytes.length % 2) != 0) { + String msg = "The input bytes to be decoded must be multiples of 4, but is multiple of {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, (bytes.length % 4)); + throw new RuntimeException(msg); + } + + if (alphabet.length != 128) { + String msg = MessageFormat.format("Alphabet does not have expected size 128 but is {0}", alphabet.length); //$NON-NLS-1$ + throw new RuntimeException(msg); + } + + if (!isEncodedByAlphabet(alphabet, bytes, 0)) + throw new RuntimeException("The data contains illegal values which are not mapped by the given alphabet!"); //$NON-NLS-1$ + + int dataLength = bytes.length / 2; + + byte[] data = new byte[dataLength]; + for (int i = 0; i < bytes.length;) { + + byte b1 = bytes[i++]; + byte b2 = bytes[i++]; + + String msgOutOfRange = "Value at index {0} is not in range of alphabet (0-127){1}"; //$NON-NLS-1$ + if (b1 < 0) { + msgOutOfRange = MessageFormat.format(msgOutOfRange, (i - 2), b1); + throw new IllegalArgumentException(msgOutOfRange); + } + if (b2 < 0) { + msgOutOfRange = MessageFormat.format(msgOutOfRange, (i - 1), b2); + throw new IllegalArgumentException(msgOutOfRange); + } + + byte c1 = alphabet[b1]; + byte c2 = alphabet[b2]; + + String msgIllegalValue = "Value at index {0} is referencing illegal value in alphabet: {1}"; //$NON-NLS-1$ + if (c1 == -1) { + msgIllegalValue = MessageFormat.format(msgIllegalValue, (i - 2), b1); + throw new IllegalArgumentException(msgIllegalValue); + } + if (c2 == -1) { + msgIllegalValue = MessageFormat.format(msgIllegalValue, (i - 2), b2); + throw new IllegalArgumentException(msgIllegalValue); + } + + int dataIndex = (i / 2) - 1; + int value = ((c1 << 4) & 0xff) | c2; + data[dataIndex] = (byte) value; + } + + return data; + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/ByteHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ByteHelper.java new file mode 100644 index 000000000..eab5b937a --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ByteHelper.java @@ -0,0 +1,267 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +/** + * @author Robert von Burg + */ +public class ByteHelper { + + /** + * Creates a long of the given byte array. They byte array must be 8 bytes long. The byte at index 0 is the highest + * byte + * + * @param bytes + * the bytes to convert to a long + * + * @return the long created from the bytes + */ + public static long toLong(byte[] bytes) { + + if (bytes.length != 8) + throw new IllegalArgumentException("The input byte array for a long must have 8 values"); //$NON-NLS-1$ + + return ((long) (bytes[0] & 0xff) << 56) // + | ((long) (bytes[1] & 0xff) << 48) // + | ((long) (bytes[2] & 0xff) << 40) // + | ((long) (bytes[3] & 0xff) << 32) // + | ((long) (bytes[4] & 0xff) << 24) // + | ((long) (bytes[5] & 0xff) << 16) // + | ((long) (bytes[6] & 0xff) << 8) // + | ((bytes[7] & 0xff)); + } + + /** + * Creates an integer of the given byte array. They byte array must be 4 bytes long. The byte at index 0 is the + * highest byte + * + * @param bytes + * the bytes to convert to an integer + * + * @return the integer created from the bytes + */ + public static int toInt(byte[] bytes) { + + if (bytes.length != 4) + throw new IllegalArgumentException("The input byte array for a long must have 4 values"); //$NON-NLS-1$ + + return ((bytes[0] & 0xff) << 24) // + | ((bytes[1] & 0xff) << 16) // + | ((bytes[2] & 0xff) << 8) // + | ((bytes[3] & 0xff)); + } + + /** + * Formats the given byte to a binary string + * + * @param b + * the byte to format to a binary string + * + * @return the binary string + */ + public static String asBinary(byte b) { + + StringBuilder sb = new StringBuilder(); + + sb.append(((b >>> 7) & 1)); + sb.append(((b >>> 6) & 1)); + sb.append(((b >>> 5) & 1)); + sb.append(((b >>> 4) & 1)); + sb.append(((b >>> 3) & 1)); + sb.append(((b >>> 2) & 1)); + sb.append(((b >>> 1) & 1)); + sb.append(((b >>> 0) & 1)); + + return sb.toString(); + } + + /** + * Formats the given byte array to a binary string, separating each byte by a space + * + * @param bytes + * the byte to format to a binary string + * + * @return the binary string + */ + public static String asBinary(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + + for (byte b : bytes) { + sb.append(asBinary(b)); + sb.append(StringHelper.SPACE); + } + + return sb.toString(); + } + + /** + * Formats the given integer to a binary string, each byte is separated by a space + * + * @param i + * the integer to format to a string + * + * @return the binary string + */ + public static String asBinary(int i) { + + StringBuilder sb = new StringBuilder(); + + sb.append(((i >>> 31) & 1)); + sb.append(((i >>> 30) & 1)); + sb.append(((i >>> 29) & 1)); + sb.append(((i >>> 28) & 1)); + sb.append(((i >>> 27) & 1)); + sb.append(((i >>> 26) & 1)); + sb.append(((i >>> 25) & 1)); + sb.append(((i >>> 24) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 23) & 1)); + sb.append(((i >>> 22) & 1)); + sb.append(((i >>> 21) & 1)); + sb.append(((i >>> 20) & 1)); + sb.append(((i >>> 19) & 1)); + sb.append(((i >>> 18) & 1)); + sb.append(((i >>> 17) & 1)); + sb.append(((i >>> 16) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 15) & 1)); + sb.append(((i >>> 14) & 1)); + sb.append(((i >>> 13) & 1)); + sb.append(((i >>> 12) & 1)); + sb.append(((i >>> 11) & 1)); + sb.append(((i >>> 10) & 1)); + sb.append(((i >>> 9) & 1)); + sb.append(((i >>> 8) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 7) & 1)); + sb.append(((i >>> 6) & 1)); + sb.append(((i >>> 5) & 1)); + sb.append(((i >>> 4) & 1)); + sb.append(((i >>> 3) & 1)); + sb.append(((i >>> 2) & 1)); + sb.append(((i >>> 1) & 1)); + sb.append(((i >>> 0) & 1)); + + return sb.toString(); + } + + /** + * Formats the given long to a binary string, each byte is separated by a space + * + * @param i + * the long to format + * + * @return the binary string + */ + public static String asBinary(long i) { + + StringBuilder sb = new StringBuilder(); + + sb.append(((i >>> 63) & 1)); + sb.append(((i >>> 62) & 1)); + sb.append(((i >>> 61) & 1)); + sb.append(((i >>> 60) & 1)); + sb.append(((i >>> 59) & 1)); + sb.append(((i >>> 58) & 1)); + sb.append(((i >>> 57) & 1)); + sb.append(((i >>> 56) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 55) & 1)); + sb.append(((i >>> 54) & 1)); + sb.append(((i >>> 53) & 1)); + sb.append(((i >>> 52) & 1)); + sb.append(((i >>> 51) & 1)); + sb.append(((i >>> 50) & 1)); + sb.append(((i >>> 49) & 1)); + sb.append(((i >>> 48) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 47) & 1)); + sb.append(((i >>> 46) & 1)); + sb.append(((i >>> 45) & 1)); + sb.append(((i >>> 44) & 1)); + sb.append(((i >>> 43) & 1)); + sb.append(((i >>> 42) & 1)); + sb.append(((i >>> 41) & 1)); + sb.append(((i >>> 40) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 39) & 1)); + sb.append(((i >>> 38) & 1)); + sb.append(((i >>> 37) & 1)); + sb.append(((i >>> 36) & 1)); + sb.append(((i >>> 35) & 1)); + sb.append(((i >>> 34) & 1)); + sb.append(((i >>> 33) & 1)); + sb.append(((i >>> 32) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 31) & 1)); + sb.append(((i >>> 30) & 1)); + sb.append(((i >>> 29) & 1)); + sb.append(((i >>> 28) & 1)); + sb.append(((i >>> 27) & 1)); + sb.append(((i >>> 26) & 1)); + sb.append(((i >>> 25) & 1)); + sb.append(((i >>> 24) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 23) & 1)); + sb.append(((i >>> 22) & 1)); + sb.append(((i >>> 21) & 1)); + sb.append(((i >>> 20) & 1)); + sb.append(((i >>> 19) & 1)); + sb.append(((i >>> 18) & 1)); + sb.append(((i >>> 17) & 1)); + sb.append(((i >>> 16) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 15) & 1)); + sb.append(((i >>> 14) & 1)); + sb.append(((i >>> 13) & 1)); + sb.append(((i >>> 12) & 1)); + sb.append(((i >>> 11) & 1)); + sb.append(((i >>> 10) & 1)); + sb.append(((i >>> 9) & 1)); + sb.append(((i >>> 8) & 1)); + + sb.append(StringHelper.SPACE); + + sb.append(((i >>> 7) & 1)); + sb.append(((i >>> 6) & 1)); + sb.append(((i >>> 5) & 1)); + sb.append(((i >>> 4) & 1)); + sb.append(((i >>> 3) & 1)); + sb.append(((i >>> 2) & 1)); + sb.append(((i >>> 1) & 1)); + sb.append(((i >>> 0) & 1)); + + return sb.toString(); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/ClassHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ClassHelper.java new file mode 100644 index 000000000..6c4a4b648 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ClassHelper.java @@ -0,0 +1,104 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.text.MessageFormat; + +/** + * Utility class for working with {@link Class Classes} + * + * @author Robert von Burg + */ +public class ClassHelper { + + /** + * Returns an instance of the class' name given by instantiating the class through an empty arguments constructor + * + * @param + * the type of the class to return + * @param className + * the name of a class to instantiate through an empty arguments constructor + * + * @return the newly instantiated object from the given class name + * + * @throws IllegalArgumentException + * if the class could not be instantiated + */ + @SuppressWarnings("unchecked") + public static T instantiateClass(String className) throws IllegalArgumentException { + try { + + Class clazz = (Class) Class.forName(className); + + return clazz.getConstructor().newInstance(); + + } catch (Exception e) { + String msg = MessageFormat.format("The class {0} could not be instantiated: ", className); //$NON-NLS-1$ + throw new IllegalArgumentException(msg, e); + } + } + + /** + * Instantiates an object for the given {@link Class} using an empty arguments constructor + * + * @param + * the type of the class to return + * @param clazz + * the {@link Class} from which a new object is to be instantiated using an empty arguments constructor + * + * @return the newly instantiated object from the given {@link Class} + * + * @throws IllegalArgumentException + * if the {@link Class} could not be instantiated + */ + public static T instantiateClass(Class clazz) throws IllegalArgumentException { + try { + + return clazz.getConstructor().newInstance(); + + } catch (Exception e) { + String msg = MessageFormat.format("The class {0} could not be instantiated: ", clazz.getName()); //$NON-NLS-1$ + throw new IllegalArgumentException(msg, e); + } + } + + /** + * Loads the {@link Class} object for the given class name + * + * @param + * the type of {@link Class} to return + * @param className + * the name of the {@link Class} to load and return + * + * @return the {@link Class} object for the given class name + * + * @throws IllegalArgumentException + * if the class could not be instantiated + */ + @SuppressWarnings("unchecked") + public static Class loadClass(String className) throws IllegalArgumentException { + try { + + Class clazz = (Class) Class.forName(className); + + return clazz; + + } catch (Exception e) { + String msg = MessageFormat.format("The class {0} could not be instantiated: ", className); //$NON-NLS-1$ + throw new IllegalArgumentException(msg, e); + } + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/DomUtil.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/DomUtil.java new file mode 100644 index 000000000..bc7acfa45 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/DomUtil.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.text.MessageFormat; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * @author Robert von Burg + */ +public class DomUtil { + + public static DocumentBuilder createDocumentBuilder() { + try { + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + return docBuilder; + } catch (ParserConfigurationException e) { + String msg = "No Xml Parser could be loaded: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, e.getMessage()); + throw new RuntimeException(msg, e); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/ExceptionHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ExceptionHelper.java new file mode 100644 index 000000000..1acebe698 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ExceptionHelper.java @@ -0,0 +1,111 @@ +/* + * Copyright 2015 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * @author Robert von Burg + */ +public class ExceptionHelper { + + /** + *

+ * Returns a message for the given {@link Throwable} + *

+ * + *

+ * A {@link NullPointerException} only has null as the message so this methods returns the class name + * in such a case + *

+ * + * @param t + * @return + */ + public static String getExceptionMessage(Throwable t) { + return StringHelper.isEmpty(t.getMessage()) ? t.getClass().getName() : t.getMessage(); + } + + /** + *

+ * Returns a message for the given {@link Throwable} + *

+ * + *

+ * A {@link NullPointerException} only has null as the message so this methods returns the class name + * in such a case + *

+ * + * @param t + * @return + */ + public static String getExceptionMessageWithCauses(Throwable t) { + if (t.getCause() == null) + return getExceptionMessage(t); + + String root = getExceptionMessageWithCauses(t.getCause()); + return getExceptionMessage(t) + "\n" + root; + } + + /** + * Formats the given {@link Throwable}'s stack trace to a string + * + * @param t + * the throwable for which the stack trace is to be formatted to string + * + * @return a string representation of the given {@link Throwable}'s stack trace + */ + public static String formatException(Throwable t) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + t.printStackTrace(writer); + return stringWriter.toString(); + } + + /** + * Formats the given {@link Throwable}'s message including causes to a string + * + * @param t + * the throwable for which the messages are to be formatted to a string + * + * @return a string representation of the given {@link Throwable}'s messages including causes + */ + public static String formatExceptionMessage(Throwable t) { + if (t.getCause() == null) + return getExceptionMessage(t); + + String root = formatExceptionMessage(t.getCause()); + return getExceptionMessage(t) + "\ncause:\n" + root; + } + + /** + * Returns the root cause for the given {@link Throwable} + * + * @param throwable + * the {@link Throwable} for which to get the root cause + * + * @return the root cause of the given {@link Throwable} + */ + public static Throwable getRootCause(Throwable throwable) { + Throwable t = throwable; + while (t.getCause() != null) { + t = t.getCause(); + } + + return t; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/FileHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/FileHelper.java new file mode 100644 index 000000000..6106cff8c --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/FileHelper.java @@ -0,0 +1,577 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.MessageDigest; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Helper class for dealing with files + * + * @author Robert von Burg + */ +public class FileHelper { + + private static final int MAX_FILE_SIZE = 50 * 1024 * 1024; + private static final Logger logger = LoggerFactory.getLogger(FileHelper.class); + + /** + * Reads the contents of a file into a byte array. + * + * @param file + * the file to read + * + * @return the contents of a file as a string + */ + public static final byte[] readFile(File file) { + if (file.length() > MAX_FILE_SIZE) + throw new RuntimeException(String.format("Only allowed to read files up to %s. File too large: %s", //$NON-NLS-1$ + humanizeFileSize(MAX_FILE_SIZE), humanizeFileSize(file.length()))); + + byte[] data = new byte[(int) file.length()]; + int pos = 0; + + try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));) { + byte[] bytes = new byte[8192]; + int read; + while ((read = in.read(bytes)) != -1) { + System.arraycopy(bytes, 0, data, pos, read); + pos += read; + } + } catch (FileNotFoundException e) { + throw new RuntimeException("Filed does not exist " + file.getAbsolutePath()); //$NON-NLS-1$ + } catch (IOException e) { + throw new RuntimeException("Could not read file " + file.getAbsolutePath()); //$NON-NLS-1$ + } + + return data; + } + + /** + * Reads the contents of a file into a string. Note, no encoding is checked. It is expected to be UTF-8 + * + * @param file + * the file to read + * + * @return the contents of a file as a string + */ + public static final String readFileToString(File file) { + + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file));) { + + StringBuilder sb = new StringBuilder(); + + String line; + + while ((line = bufferedReader.readLine()) != null) { + sb.append(line + "\n"); //$NON-NLS-1$ + } + + return sb.toString(); + + } catch (FileNotFoundException e) { + throw new RuntimeException("File does not exist " + file.getAbsolutePath()); //$NON-NLS-1$ + } catch (IOException e) { + throw new RuntimeException("Could not read file " + file.getAbsolutePath()); //$NON-NLS-1$ + } + } + + /** + * Reads the contents of a {@link InputStream} into a string. Note, no encoding is checked. It is expected to be + * UTF-8 + * + * @param stream + * the stream to read + * + * @return the contents of a file as a string + */ + public static final String readStreamToString(InputStream stream) { + + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));) { + + StringBuilder sb = new StringBuilder(); + + String line; + + while ((line = bufferedReader.readLine()) != null) { + sb.append(line + "\n"); //$NON-NLS-1$ + } + + return sb.toString(); + + } catch (IOException e) { + throw new RuntimeException("Could not read strean " + stream); //$NON-NLS-1$ + } + } + + /** + * Writes the given byte array to the given file + * + * @param bytes + * the data to write to the file + * @param dstFile + * the path to which to write the data + */ + public static final void writeToFile(byte[] bytes, File dstFile) { + + try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dstFile));) { + out.write(bytes); + } catch (FileNotFoundException e) { + throw new RuntimeException("Filed does not exist " + dstFile.getAbsolutePath()); //$NON-NLS-1$ + } catch (IOException e) { + throw new RuntimeException("Could not write to file " + dstFile.getAbsolutePath()); //$NON-NLS-1$ + } + } + + /** + * Writes the string to dstFile + * + * @param string + * string to write to file + * @param dstFile + * the file to write to + */ + public static final void writeStringToFile(String string, File dstFile) { + + try (BufferedWriter bufferedwriter = new BufferedWriter(new FileWriter(dstFile));) { + bufferedwriter.write(string); + } catch (FileNotFoundException e) { + throw new RuntimeException("Filed does not exist " + dstFile.getAbsolutePath()); //$NON-NLS-1$ + } catch (IOException e) { + throw new RuntimeException("Could not write to file " + dstFile.getAbsolutePath()); //$NON-NLS-1$ + } + } + + /** + * Deletes files recursively. No question asked, but logging is done in case of problems + * + * @param file + * the file to delete + * @param log + * @return true if all went well, and false if it did not work. The log will contain the problems encountered + */ + public final static boolean deleteFile(File file, boolean log) { + return FileHelper.deleteFiles(new File[] { file }, log); + } + + /** + * Deletes files recursively. No question asked, but logging is done in case of problems + * + * @param files + * the files to delete + * @param log + * @return true if all went well, and false if it did not work. The log will contain the problems encountered + */ + public final static boolean deleteFiles(File[] files, boolean log) { + + boolean worked = true; + for (int i = 0; i < files.length; i++) { + File file = files[i]; + if (file.isDirectory()) { + boolean done = FileHelper.deleteFiles(file.listFiles(), log); + if (!done) { + worked = false; + FileHelper.logger.warn("Could not empty the directory: " + file.getAbsolutePath()); //$NON-NLS-1$ + } else { + done = file.delete(); + if (done) { + if (log) + FileHelper.logger.info("Deleted DIR " + file.getAbsolutePath()); //$NON-NLS-1$ + } else { + worked = false; + FileHelper.logger.warn("Could not delete the directory: " + file.getAbsolutePath()); //$NON-NLS-1$ + } + } + } else { + boolean done = file.delete(); + if (done) { + if (log) + FileHelper.logger.info("Deleted FILE " + file.getAbsolutePath()); //$NON-NLS-1$ + } else { + worked = false; + FileHelper.logger.warn(("Could not delete the file: " + file.getAbsolutePath())); //$NON-NLS-1$ + } + } + } + return worked; + } + + /** + *

+ * Copy a given list of {@link File Files}. Recursively copies the files and directories to the destination. + *

+ * + * @param srcFiles + * The source files to copy + * @param dstDirectory + * The destination where to copy the files + * @param checksum + * if true, then a MD5 checksum is made to validate copying + * @return true if and only if the copying succeeded; false otherwise + */ + public final static boolean copy(File[] srcFiles, File dstDirectory, boolean checksum) { + + if (!dstDirectory.isDirectory() || !dstDirectory.canWrite()) { + String msg = "Destination is not a directory or is not writeable: {0}"; //$NON-NLS-1$ + throw new IllegalArgumentException(MessageFormat.format(msg, dstDirectory.getAbsolutePath())); + } + + for (File srcFile : srcFiles) { + + File dstFile = new File(dstDirectory, srcFile.getName()); + if (srcFile.isDirectory()) { + dstFile.mkdir(); + if (!copy(srcFile.listFiles(), dstFile, checksum)) { + String msg = "Failed to copy contents of {0} to {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, srcFile.getAbsolutePath(), dstFile.getAbsolutePath()); + logger.error(msg); + return false; + } + } else { + if (!copy(srcFile, dstFile, checksum)) { + return false; + } + } + } + + return true; + } + + /** + * Copy a {@link File} The renameTo method does not allow action across NFS mounted filesystems this method is the + * workaround + * + * @param fromFile + * The existing File + * @param toFile + * The new File + * @param checksum + * if true, then a MD5 checksum is made to validate copying + * @return true if and only if the renaming succeeded; false otherwise + */ + public final static boolean copy(File fromFile, File toFile, boolean checksum) { + + try (BufferedInputStream inBuffer = new BufferedInputStream(new FileInputStream(fromFile)); + BufferedOutputStream outBuffer = new BufferedOutputStream(new FileOutputStream(toFile));) { + + int theByte = 0; + + while ((theByte = inBuffer.read()) > -1) { + outBuffer.write(theByte); + } + + outBuffer.flush(); + + if (checksum) { + String fromFileMD5 = StringHelper.getHexString(FileHelper.hashFileMd5(fromFile)); + String toFileMD5 = StringHelper.getHexString(FileHelper.hashFileMd5(toFile)); + if (!fromFileMD5.equals(toFileMD5)) { + FileHelper.logger.error(MessageFormat.format( + "Copying failed, as MD5 sums are not equal: {0} / {1}", fromFileMD5, toFileMD5)); //$NON-NLS-1$ + toFile.delete(); + + return false; + } + } + + // cleanup if files are not the same length + if (fromFile.length() != toFile.length()) { + String msg = "Copying failed, as new files are not the same length: {0} / {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, fromFile.length(), toFile.length()); + FileHelper.logger.error(msg); + toFile.delete(); + + return false; + } + + } catch (Exception e) { + String msg = MessageFormat.format("Failed to copy path from {0} to + {1} due to:", fromFile, toFile); //$NON-NLS-1$ + FileHelper.logger.error(msg, e); + return false; + } + + return true; + } + + /** + * Move a File The renameTo method does not allow action across NFS mounted filesystems this method is the + * workaround + * + * @param fromFile + * The existing File + * @param toFile + * The new File + * @return true if and only if the renaming succeeded; false otherwise + */ + public final static boolean move(File fromFile, File toFile) { + + if (fromFile.renameTo(toFile)) { + return true; + } + + FileHelper.logger.warn("Simple File.renameTo failed, trying copy/delete..."); //$NON-NLS-1$ + + // delete if copy was successful, otherwise move will fail + if (FileHelper.copy(fromFile, toFile, true)) { + FileHelper.logger.info("Deleting fromFile: " + fromFile.getAbsolutePath()); //$NON-NLS-1$ + return fromFile.delete(); + } + + return false; + } + + /** + * Finds the common parent for the files in the given list + * + * @param files + * the files to find the common parent for + * + * @return the {@link File} representing the common parent, or null if there is none + */ + public static File findCommonParent(List files) { + + // be gentle with bad input data + if (files.size() == 0) + return null; + if (files.size() == 1) + return files.get(0).getParentFile(); + + File commonParent = null; + int commonParentDepth = -1; + + // find the common parent among all the files + for (int i = 0; i < files.size() - 1; i++) { + + // get first file + File file = files.get(i); + + // get list of parents for this file + List parents = new ArrayList<>(); + File parent = file.getParentFile(); + while (parent != null) { + parents.add(parent); + parent = parent.getParentFile(); + } + // reverse + Collections.reverse(parents); + + // and now the same for the next file + File fileNext = files.get(i + 1); + List parentsNext = new ArrayList<>(); + File parentNext = fileNext.getParentFile(); + while (parentNext != null) { + parentsNext.add(parentNext); + parentNext = parentNext.getParentFile(); + } + // reverse + Collections.reverse(parentsNext); + + //logger.info("Files: " + file + " / " + fileNext); + + // now find the common parent + File newCommonParent = null; + int newCommonParentDepth = -1; + for (int j = 0; j < (parents.size()); j++) { + + // don't overflow the size of the next list of parents + if (j >= parentsNext.size()) + break; + + // if we once found a common parent, and our current depth is + // greater than the one for the common parent, then stop as + // there can't be a deeper parent + if (commonParent != null && j > commonParentDepth) + break; + + // get the next parents to compare + File aParent = parents.get(j); + File bParent = parentsNext.get(j); + + //logger.info("Comparing " + aParent + " |||| " + bParent); + + // if they parent are the same, then break, as we won't + // have another match + if (!aParent.equals(bParent)) + break; + + // save the parent and the depth where we found the parent + newCommonParent = aParent; + newCommonParentDepth = j; + } + + // if no common parent was found, then break as there won't be one + if (commonParent == null && newCommonParent == null) + break; + + // if there is no new common parent, then check the next file + if (newCommonParent == null) + continue; + + // store the common parent + commonParent = newCommonParent; + commonParentDepth = newCommonParentDepth; + //logger.info("Temporary common parent: (" + commonParentDepth + ") " + commonParent); + } + + //logger.info("Common parent: " + commonParent); + return commonParent; + } + + /** + * Returns the size of the file in a human readable form. Everything smaller than 1024 bytes is returned as x bytes, + * next is KB, then MB and then GB + * + * @param file + * the file for which the humanized size is to be returned + * + * @return the humanized form of the files size + */ + public final static String humanizeFileSize(File file) { + return FileHelper.humanizeFileSize(file.length()); + } + + /** + * Returns the size of the file in a human readable form. Everything smaller than 1024 bytes is returned as x bytes, + * next is KB, then MB and then GB + * + * @param fileSize + * the size of a file for which the humanized size is to be returned + * + * @return the humanized form of the files size + */ + @SuppressWarnings("nls") + public final static String humanizeFileSize(long fileSize) { + if (fileSize < 1024) + return String.format("%d bytes", fileSize); + + if (fileSize < 1048576) + return String.format("%.1f KB", (fileSize / 1024.0d)); + + if (fileSize < 1073741824) + return String.format("%.1f MB", (fileSize / 1048576.0d)); + + return String.format("%.1f GB", (fileSize / 1073741824.0d)); + } + + /** + * Creates the MD5 hash of the given file, returning the hash as a byte array. Use + * {@link StringHelper#getHexString(byte[])} to create a HEX string of the bytes + * + * @param file + * the file to hash + * + * @return the hash as a byte array + */ + public static byte[] hashFileMd5(File file) { + return FileHelper.hashFile(file, "MD5"); //$NON-NLS-1$ + } + + /** + * Creates the SHA1 hash of the given file, returning the hash as a byte array. Use + * {@link StringHelper#getHexString(byte[])} to create a HEX string of the bytes + * + * @param file + * the file to hash + * + * @return the hash as a byte array + */ + public static byte[] hashFileSha1(File file) { + return FileHelper.hashFile(file, "SHA-1"); //$NON-NLS-1$ + } + + /** + * Creates the SHA256 hash of the given file, returning the hash as a byte array. Use + * {@link StringHelper#getHexString(byte[])} to create a HEX string of the bytes + * + * @param file + * the file to hash + * + * @return the hash as a byte array + */ + public static byte[] hashFileSha256(File file) { + return FileHelper.hashFile(file, "SHA-256"); //$NON-NLS-1$ + } + + /** + * Creates the hash of the given file with the given algorithm, returning the hash as a byte array. Use + * {@link StringHelper#getHexString(byte[])} to create a HEX string of the bytes + * + * @param file + * the file to hash + * @param algorithm + * the hashing algorithm to use + * + * @return the hash as a byte array + */ + public static byte[] hashFile(File file, String algorithm) { + try (InputStream fis = new FileInputStream(file);) { + + byte[] buffer = new byte[1024]; + MessageDigest complete = MessageDigest.getInstance(algorithm); + int numRead; + do { + numRead = fis.read(buffer); + if (numRead > 0) { + complete.update(buffer, 0, numRead); + } + } while (numRead != -1); + + return complete.digest(); + } catch (Exception e) { + throw new RuntimeException("Something went wrong while hashing file: " + file.getAbsolutePath()); //$NON-NLS-1$ + } + } + + /** + * Helper method to append bytes to a specified file. The file is created if it does not exist otherwise the bytes + * are simply appended + * + * @param dstFile + * the file to append to + * @param bytes + * the bytes to append + */ + public static void appendFilePart(File dstFile, byte[] bytes) { + + try (FileOutputStream outputStream = new FileOutputStream(dstFile, true);) { + + outputStream.write(bytes); + outputStream.flush(); + + } catch (IOException e) { + throw new RuntimeException("Could not create and append the bytes to the file " + dstFile.getAbsolutePath()); //$NON-NLS-1$ + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/MathHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/MathHelper.java new file mode 100644 index 000000000..cf2ccbf90 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/MathHelper.java @@ -0,0 +1,125 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * A helper class that contains mathematical computations that can be used throughout. + * + * @author Martin Smock + * @author Michael Gatto + */ +public class MathHelper { + + public static final double PRECISION = 1.0E08; + public static final int PRECISION_DIGITS = 3; + + /** + * Check if the two values are equal with respect to the precision + * + * @param firstValue + * the first value to compare + * @param secondValue + * the second value to compare to + * @return boolean True, if the two values are equal under the set precision. Fales, otherwise. + */ + public static boolean isEqualPrecision(double firstValue, double secondValue) { + + return (java.lang.Math.abs(firstValue - secondValue) < (1.0d / PRECISION)); + } + + /** + * Comparison between the two values. Given the precision, this function determines if the given value is smaller + * than the given bound. + *

+ * Note: this implementation tests if the value < bound, and if this is not so, checks if the values are equal under + * the precision. Thus, it's efficient whenever the value is expected to be smaller than the bound. + * + * @param value + * The value to check + * @param bound + * The bound given + * @return true, if value < bound under the given precision. False, otherwise. + */ + public static boolean isSmallerEqualPrecision(double value, double bound) { + if (value < bound) + return true; + return isEqualPrecision(value, bound); + } + + /** + * Comparison between two values. Given the precision, this function determines if the given value is greater than + * the given bound. + *

+ * Note: This implementation tests if value > bound and, if it is so, if equality does NOT hold. Thus, it is + * efficient whenever the value is not expected to be greater than the bound. + * + * @param value + * The value to check + * @param bound + * The bound given. + * @return true, if value > bound and the values do not test equal under precision. False, otherwise. + */ + public static boolean isGreaterPrecision(double value, double bound) { + return (value > bound) && !isEqualPrecision(value, bound); + } + + /** + *

+ * Rounds the given double value to the number of decimals + *

+ * + *

+ * Warning: Do not use the returned value for further calculations. Always finish calculates and use one of + * the following methods: + *

    + *
  • {@link #isEqualPrecision(double, double)},
  • + *
  • {@link #isGreaterPrecision(double, double)} or
  • + *
  • {@link #isSmallerEqualPrecision(double, double)}
  • + *
+ * to test on equality or greater than/ smaller than + *

+ * + * @param value + * the double value to round + * @param decimals + * number of decimals + * + * @return the rounded number + */ + public static double toPrecision(double value, int decimals) { + if (value == 0.0) + return 0.0; + if (Double.isNaN(value)) + return Double.NaN; + if (value == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + if (value == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + return new BigDecimal(value).setScale(decimals, RoundingMode.HALF_EVEN).doubleValue(); + } + + /** + * Returns the value with the precision where precision is set to {@link #PRECISION_DIGITS} + * + * @see #toPrecision(double, int) + */ + public static double toPrecision(double value) { + return toPrecision(value, PRECISION_DIGITS); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/ProcessHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ProcessHelper.java new file mode 100644 index 000000000..a157b100c --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/ProcessHelper.java @@ -0,0 +1,172 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Robert von Burg + */ +public class ProcessHelper { + + private static final Logger logger = LoggerFactory.getLogger(ProcessHelper.class); + + public static ProcessResult runCommand(String... commandAndArgs) { + return runCommand(null, commandAndArgs); + } + + public static ProcessResult runCommand(File workingDirectory, String... commandAndArgs) { + return runCommand(30, TimeUnit.SECONDS, workingDirectory, commandAndArgs); + } + + public static ProcessResult runCommand(long timeout, TimeUnit unit, String... commandAndArgs) { + return runCommand(timeout, unit, null, commandAndArgs); + } + + public static ProcessResult runCommand(long timeout, TimeUnit unit, File workingDirectory, + String... commandAndArgs) { + + if (workingDirectory != null && !workingDirectory.isDirectory()) { + String msg = "Working directory does not exist or is not a directory at {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, workingDirectory.getAbsolutePath()); + throw new RuntimeException(msg); + } + if (commandAndArgs == null || commandAndArgs.length == 0) + throw new RuntimeException("No command passed!"); //$NON-NLS-1$ + + final StringBuffer sb = new StringBuffer(); + sb.append("=====================================\n"); //$NON-NLS-1$ + try { + + ProcessBuilder pb = new ProcessBuilder(commandAndArgs); + pb.environment(); + pb.directory(workingDirectory); + + long start = System.nanoTime(); + logger.info(MessageFormat.format("Starting command (Timeout {0} {1}) {2}", timeout, unit.name(), + Arrays.stream(commandAndArgs).collect(Collectors.joining(" ")))); + final Process process = pb.start(); + int[] returnValue = new int[1]; + + try (BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream())); + BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));) { + + Thread errorIn = new Thread(() -> readStream(sb, "[ERROR] ", errorStream), "errorIn"); + errorIn.start(); + + Thread infoIn = new Thread(() -> readStream(sb, "[INFO] ", inputStream), "infoIn"); + infoIn.start(); + + boolean ok = process.waitFor(timeout, unit); + if (!ok) + logger.error("Command failed to end before timeout or failed to execute."); + + if (!process.isAlive()) { + returnValue[0] = process.exitValue(); + } else { + logger.error("Forcibly destroying as still running..."); + process.destroyForcibly(); + process.waitFor(5, TimeUnit.SECONDS); + returnValue[0] = -1; + } + + errorIn.join(100l); + infoIn.join(100l); + sb.append("=====================================\n"); //$NON-NLS-1$ + } + + logger.info("Command ended after " + StringHelper.formatNanoDuration(System.nanoTime() - start)); + return new ProcessResult(returnValue[0], sb.toString(), null); + + } catch (IOException e) { + throw new RuntimeException("Failed to perform command: " + e.getLocalizedMessage(), e); //$NON-NLS-1$ + } catch (InterruptedException e) { + logger.error("Interrupted!"); //$NON-NLS-1$ + sb.append("[FATAL] Interrupted"); //$NON-NLS-1$ + return new ProcessResult(-1, sb.toString(), e); + } + } + + public static class ProcessResult { + public final int returnValue; + public final String processOutput; + public final Throwable throwable; + + public ProcessResult(int returnValue, String processOutput, Throwable t) { + this.returnValue = returnValue; + this.processOutput = processOutput; + this.throwable = t; + } + } + + static void readStream(StringBuffer sb, String prefix, BufferedReader bufferedReader) { + String line; + try { + while ((line = bufferedReader.readLine()) != null) { + sb.append(prefix + line + StringHelper.NEW_LINE); + } + } catch (IOException e) { + String msg = "Faild to read from {0} stream: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, prefix, e.getMessage()); + sb.append("[FATAL] "); //$NON-NLS-1$ + sb.append(msg); + sb.append(StringHelper.NEW_LINE); + } + } + + public static void openFile(File pdfPath) { + + ProcessResult processResult; + if (SystemHelper.isLinux()) { + processResult = runCommand("xdg-open " + pdfPath.getAbsolutePath()); //$NON-NLS-1$ + } else if (SystemHelper.isMacOS()) { + processResult = runCommand("open " + pdfPath.getAbsolutePath()); //$NON-NLS-1$ + } else if (SystemHelper.isWindows()) { + // remove the first char (/) from the report path (/D:/temp.....) + String pdfFile = pdfPath.getAbsolutePath(); + if (pdfFile.charAt(0) == '/') + pdfFile = pdfFile.substring(1); + processResult = runCommand("rundll32 url.dll,FileProtocolHandler " + pdfFile); //$NON-NLS-1$ + } else { + String msg = MessageFormat.format("Unexpected OS: {0}", SystemHelper.osName); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + logProcessResult(processResult); + } + + public static void logProcessResult(ProcessResult processResult) { + if (processResult.returnValue == 0) { + logger.info("Process executed successfully"); //$NON-NLS-1$ + } else if (processResult.returnValue == -1) { + logger.error("Process execution failed:\n" + processResult.processOutput); //$NON-NLS-1$ + logger.error(processResult.throwable.getMessage(), processResult.throwable); + } else { + String msg = "Process execution was not successful with return value:{0}\n{1}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, processResult.returnValue, processResult.processOutput)); + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/PropertiesHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/PropertiesHelper.java new file mode 100644 index 000000000..ec787c66b --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/PropertiesHelper.java @@ -0,0 +1,187 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.text.MessageFormat; +import java.util.Properties; + +/** + * @author Robert von Burg + */ +public class PropertiesHelper { + + /** + * Returns the property with the given key from the given {@link Properties}. If def is null, and the property is + * not set, then a {@link RuntimeException} is thrown + * + * @param properties + * the {@link Properties} from which to retrieve the property + * @param context + * The context should be the name of the caller, so that stack trace gives enough detail as to which + * class expected the configuration property if no property was found + * @param key + * the key of the property to return + * @param def + * the default value, if null, then an exception will be thrown if the property is not set + * + * @return the property under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static String getProperty(Properties properties, String context, String key, String def) + throws RuntimeException { + String property = properties.getProperty(key, def); + if (property == null) { + String msg = "[{0}] Property {1} is not set, and no default was given!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, context, key); + throw new RuntimeException(msg); + } + + return property; + } + + /** + * Returns the {@link System#getProperty(String)} with the given key. If def is null, and the property is not set, + * then a {@link RuntimeException} is thrown + * + * @param context + * The context should be the name of the caller, so that stack trace gives enough detail as to which + * class expected the configuration property if no property was found + * @param key + * the key of the property to return + * @param def + * the default value, if null, then an exception will be thrown if the property is not set + * + * @return the property under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static String getProperty(String context, String key, String def) throws RuntimeException { + return getProperty(System.getProperties(), context, key, def); + } + + /** + * Delegates to {@link #getProperty(Properties, String, String, String)} but returns the value as a {@link Boolean} + * where {@link Boolean#valueOf(String)} defines the actual value + * + * @param properties + * the {@link Properties} from which to retrieve the property + * @return the property as a {@link Boolean} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Boolean getPropertyBool(Properties properties, String context, String key, Boolean def) + throws RuntimeException { + return Boolean.valueOf(getProperty(properties, context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(String, String, String)} but returns the value as a {@link Boolean} where + * {@link Boolean#valueOf(String)} defines the actual value + * + * @return the property as a {@link Boolean} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Boolean getPropertyBool(String context, String key, Boolean def) throws RuntimeException { + return Boolean.valueOf(getProperty(context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(Properties, String, String, String)} but returns the value as an {@link Integer} + * where {@link Integer#valueOf(String)} defines the actual value + * + * @return the property as a {@link Integer} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Integer getPropertyInt(Properties properties, String context, String key, Integer def) + throws RuntimeException { + return Integer.valueOf(getProperty(properties, context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(String, String, String)} but returns the value as an {@link Integer} where + * {@link Integer#valueOf(String)} defines the actual value + * + * @return the property as a {@link Integer} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Integer getPropertyInt(String context, String key, Integer def) throws RuntimeException { + return Integer.valueOf(getProperty(context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(Properties, String, String, String)} but returns the value as an {@link Double} + * where {@link Double#valueOf(String)} defines the actual value + * + * @return the property as a {@link Double} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Double getPropertyDouble(Properties properties, String context, String key, Double def) + throws RuntimeException { + return Double.valueOf(getProperty(properties, context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(String, String, String)} but returns the value as an {@link Double} where + * {@link Double#valueOf(String)} defines the actual value + * + * @return the property as a {@link Double} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Double getPropertyDouble(String context, String key, Double def) throws RuntimeException { + return Double.valueOf(getProperty(context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(Properties, String, String, String)} but returns the value as an {@link Long} + * where {@link Long#valueOf(String)} defines the actual value + * + * @return the property as a {@link Long} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Long getPropertyLong(Properties properties, String context, String key, Long def) + throws RuntimeException { + return Long.valueOf(getProperty(properties, context, key, def == null ? null : def.toString())); + } + + /** + * Delegates to {@link #getProperty(String, String, String)} but returns the value as an {@link Long} where + * {@link Long#valueOf(String)} defines the actual value + * + * @return the property as a {@link Long} under the given key + * + * @throws RuntimeException + * if the property is not set and def is null + */ + public static Long getPropertyLong(String context, String key, Long def) throws RuntimeException { + return Long.valueOf(getProperty(context, key, def == null ? null : def.toString())); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/StringHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/StringHelper.java new file mode 100644 index 000000000..2a11a0e1d --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/StringHelper.java @@ -0,0 +1,717 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.MessageFormat; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A helper class to perform different actions on {@link String}s + * + * @author Robert von Burg + */ +public class StringHelper { + + public static final String NEW_LINE = "\n"; //$NON-NLS-1$ + public static final String EMPTY = ""; //$NON-NLS-1$ + public static final String SPACE = " "; //$NON-NLS-1$ + public static final String NULL = "null"; //$NON-NLS-1$ + public static final String DASH = "-"; //$NON-NLS-1$ + public static final String UNDERLINE = "_"; //$NON-NLS-1$ + public static final String COMMA = ","; //$NON-NLS-1$ + public static final String DOT = "."; //$NON-NLS-1$ + public static final String SEMICOLON = ";"; //$NON-NLS-1$ + public static final String COLON = ":"; //$NON-NLS-1$ + + private static final Logger logger = LoggerFactory.getLogger(StringHelper.class); + + /** + * the semi-unique id which is incremented on every {@link #getUniqueId()}-method call + */ + private static long uniqueId = System.currentTimeMillis() - 1119953500000l; + + /** + * Hex char table for fast calculating of hex values + */ + private static final byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', + (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', + (byte) 'e', (byte) 'f' }; + + /** + * Converts each byte of the given byte array to a HEX value and returns the concatenation of these values + * + * @param raw + * the bytes to convert to String using numbers in hexadecimal + * + * @return the encoded string + * + * @throws RuntimeException + */ + public static String getHexString(byte[] raw) throws RuntimeException { + try { + byte[] hex = new byte[2 * raw.length]; + int index = 0; + + for (byte b : raw) { + int v = b & 0xFF; + hex[index++] = HEX_CHAR_TABLE[v >>> 4]; + hex[index++] = HEX_CHAR_TABLE[v & 0xF]; + } + + return new String(hex, "ASCII"); //$NON-NLS-1$ + + } catch (UnsupportedEncodingException e) { + String msg = MessageFormat.format("Something went wrong while converting to HEX: {0}", e.getMessage()); //$NON-NLS-1$ + throw new RuntimeException(msg, e); + } + } + + /** + * Returns a byte array of a given string by converting each character of the string to a number base 16 + * + * @param encoded + * the string to convert to a byt string + * + * @return the encoded byte stream + */ + public static byte[] fromHexString(String encoded) { + if ((encoded.length() % 2) != 0) + throw new IllegalArgumentException("Input string must contain an even number of characters."); //$NON-NLS-1$ + + final byte result[] = new byte[encoded.length() / 2]; + final char enc[] = encoded.toCharArray(); + for (int i = 0; i < enc.length; i += 2) { + StringBuilder curr = new StringBuilder(2); + curr.append(enc[i]).append(enc[i + 1]); + result[i / 2] = (byte) Integer.parseInt(curr.toString(), 16); + } + + return result; + } + + /** + * Generates the MD5 Hash of a string and converts it to a HEX string + * + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static String hashMd5AsHex(String string) { + return getHexString(hashMd5(string.getBytes())); + } + + /** + * Generates the MD5 Hash of a string. Use {@link StringHelper#getHexString(byte[])} to convert the byte array to a + * Hex String which is printable + * + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hashMd5(String string) { + return hashMd5(string.getBytes()); + } + + /** + * Generates the MD5 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array to + * a Hex String which is printable + * + * @param bytes + * the bytes to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hashMd5(byte[] bytes) { + return hash("MD5", bytes); //$NON-NLS-1$ + } + + /** + * Generates the SHA1 Hash of a string and converts it to a HEX String + * + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static String hashSha1AsHex(String string) { + return getHexString(hashSha1(string.getBytes())); + } + + /** + * Generates the SHA1 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to a + * Hex String which is printable + * + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hashSha1(String string) { + return hashSha1(string.getBytes()); + } + + /** + * Generates the SHA1 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array + * to a Hex String which is printable + * + * @param bytes + * the bytes to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hashSha1(byte[] bytes) { + return hash("SHA-1", bytes); //$NON-NLS-1$ + } + + /** + * Generates the SHA-256 Hash of a string and converts it to a HEX String + * + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static String hashSha256AsHex(String string) { + return getHexString(hashSha256(string.getBytes())); + } + + /** + * Generates the SHA-256 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to + * a Hex String which is printable + * + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hashSha256(String string) { + return hashSha256(string.getBytes()); + } + + /** + * Generates the SHA1 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array + * to a Hex String which is printable + * + * @param bytes + * the bytes to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hashSha256(byte[] bytes) { + return hash("SHA-256", bytes); //$NON-NLS-1$ + } + + /** + * Returns the hash of an algorithm + * + * @param algorithm + * the algorithm to use + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static String hashAsHex(String algorithm, String string) { + return getHexString(hash(algorithm, string)); + } + + /** + * Returns the hash of an algorithm + * + * @param algorithm + * the algorithm to use + * @param string + * the string to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hash(String algorithm, String string) { + try { + + MessageDigest digest = MessageDigest.getInstance(algorithm); + byte[] hashArray = digest.digest(string.getBytes()); + + return hashArray; + + } catch (NoSuchAlgorithmException e) { + String msg = MessageFormat.format("Algorithm {0} does not exist!", algorithm); //$NON-NLS-1$ + throw new RuntimeException(msg, e); + } + } + + /** + * Returns the hash of an algorithm + * + * @param algorithm + * the algorithm to use + * @param bytes + * the bytes to hash + * + * @return the hash or null, if an exception was thrown + */ + public static String hashAsHex(String algorithm, byte[] bytes) { + return getHexString(hash(algorithm, bytes)); + } + + /** + * Returns the hash of an algorithm + * + * @param algorithm + * the algorithm to use + * @param bytes + * the bytes to hash + * + * @return the hash or null, if an exception was thrown + */ + public static byte[] hash(String algorithm, byte[] bytes) { + try { + + MessageDigest digest = MessageDigest.getInstance(algorithm); + byte[] hashArray = digest.digest(bytes); + + return hashArray; + + } catch (NoSuchAlgorithmException e) { + String msg = MessageFormat.format("Algorithm {0} does not exist!", algorithm); //$NON-NLS-1$ + throw new RuntimeException(msg, e); + } + } + + /** + * Normalizes the length of a String. Does not shorten it when it is too long, but lengthens it, depending on the + * options set: adding the char at the beginning or appending it at the end + * + * @param value + * string to normalize + * @param length + * length string must have + * @param beginning + * add at beginning of value + * @param c + * char to append when appending + * @return the new string + */ + public static String normalizeLength(String value, int length, boolean beginning, char c) { + return normalizeLength(value, length, beginning, false, c); + } + + /** + * Normalizes the length of a String. Shortens it when it is too long, giving out a logger warning, or lengthens it, + * depending on the options set: appending the char at the beginning or the end + * + * @param value + * string to normalize + * @param length + * length string must have + * @param beginning + * append at beginning of value + * @param shorten + * allow shortening of value + * @param c + * char to append when appending + * @return the new string + */ + public static String normalizeLength(String value, int length, boolean beginning, boolean shorten, char c) { + + if (value.length() == length) + return value; + + if (value.length() < length) { + + String tmp = value; + while (tmp.length() != length) { + if (beginning) { + tmp = c + tmp; + } else { + tmp = tmp + c; + } + } + + return tmp; + + } else if (shorten) { + + logger.warn(MessageFormat.format("Shortening length of value: {0}", value)); //$NON-NLS-1$ + logger.warn(MessageFormat.format("Length is: {0} max: {1}", value.length(), length)); //$NON-NLS-1$ + + return value.substring(0, length); + } + + return value; + } + + /** + * Calls {@link #replacePropertiesIn(Properties, String)}, with {@link System#getProperties()} as input + * + * @return a new string with all defined system properties replaced or if an error occurred the original value is + * returned + */ + public static String replaceSystemPropertiesIn(String value) { + return replacePropertiesIn(System.getProperties(), value); + } + + /** + * Traverses the given string searching for occurrences of ${...} sequences. Theses sequences are replaced with a + * {@link Properties#getProperty(String)} value if such a value exists in the properties map. If the value of the + * sequence is not in the properties, then the sequence is not replaced + * + * @param properties + * the {@link Properties} in which to get the value + * @param value + * the value in which to replace any system properties + * + * @return a new string with all defined properties replaced or if an error occurred the original value is returned + */ + public static String replacePropertiesIn(Properties properties, String value) { + + return replacePropertiesIn(properties, '$', value); + } + + /** + * Traverses the given string searching for occurrences of prefix{...} sequences. Theses sequences are + * replaced with a {@link Properties#getProperty(String)} value if such a value exists in the properties map. If the + * value of the sequence is not in the properties, then the sequence is not replaced + * + * @param properties + * the {@link Properties} in which to get the value + * @param prefix + * the prefix to use, for instance use $ to replace occurrences of ${...} + * @param value + * the value in which to replace any system properties + * + * @return a new string with all defined properties replaced or if an error occurred the original value is returned + */ + public static String replacePropertiesIn(Properties properties, char prefix, String value) { + + String prefixS = String.valueOf(prefix); + + // get a copy of the value + String tmpValue = value; + + // get first occurrence of $ character + int pos = -1; + int stop = 0; + + // loop on $ character positions + while ((pos = tmpValue.indexOf(prefix, pos + 1)) != -1) { + + // if pos+1 is not { character then continue + if (tmpValue.charAt(pos + 1) != '{') { + continue; + } + + // find end of sequence with } character + stop = tmpValue.indexOf('}', pos + 1); + + // if no stop found, then break as another sequence should be able to start + if (stop == -1) { + logger.error(MessageFormat.format("Sequence starts at offset {0} but does not end!", pos)); //$NON-NLS-1$ + tmpValue = value; + break; + } + + // get sequence enclosed by pos and stop + String sequence = tmpValue.substring(pos + 2, stop); + + // make sure sequence doesn't contain $ { } characters + if (sequence.contains(prefixS) || sequence.contains("{") || sequence.contains("}")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + String msg = "Enclosed sequence in offsets {0} - {1} contains one of the illegal chars: {2} { }: {3}"; + msg = MessageFormat.format(msg, pos, stop, prefixS, sequence); + logger.error(msg); + tmpValue = value; + break; + } + + // sequence is good, so see if we have a property for it + String property = properties.getProperty(sequence, StringHelper.EMPTY); + + // if no property exists, then log and continue + if (property.isEmpty()) { + // logger.warn("No system property found for sequence " + sequence); + continue; + } + + // property exists, so replace in value + tmpValue = tmpValue.replace(prefixS + "{" + sequence + "}", property); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return tmpValue; + } + + /** + * Calls {@link #replaceProperties(Properties, Properties)} with null as the second argument. This allows for + * replacing all properties with itself + * + * @param properties + * the properties in which the values must have any ${...} replaced by values of the respective key + */ + public static void replaceProperties(Properties properties) { + replaceProperties(properties, null); + } + + /** + * Checks every value in the {@link Properties} and then then replaces any ${...} variables with keys in this + * {@link Properties} value using {@link StringHelper#replacePropertiesIn(Properties, String)} + * + * @param properties + * the properties in which the values must have any ${...} replaced by values of the respective key + * @param altProperties + * if properties does not contain the ${...} key, then try these alternative properties + */ + public static void replaceProperties(Properties properties, Properties altProperties) { + + for (Object keyObj : properties.keySet()) { + String key = (String) keyObj; + String property = properties.getProperty(key); + String newProperty = replacePropertiesIn(properties, property); + + // try first properties + if (!property.equals(newProperty)) { + // logger.info("Key " + key + " has replaced property " + property + " with new value " + newProperty); + properties.put(key, newProperty); + } else if (altProperties != null) { + + // try alternative properties + newProperty = replacePropertiesIn(altProperties, property); + if (!property.equals(newProperty)) { + // logger.info("Key " + key + " has replaced property " + property + " from alternative properties with new value " + newProperty); + properties.put(key, newProperty); + } + } + } + } + + /** + * This is a helper method with which it is possible to print the location in the two given strings where they start + * to differ. The length of string returned is currently 40 characters, or less if either of the given strings are + * shorter. The format of the string is 3 lines. The first line has information about where in the strings the + * difference occurs, and the second and third lines contain contexts + * + * @param s1 + * the first string + * @param s2 + * the second string + * + * @return the string from which the strings differ with a length of 40 characters within the original strings + */ + public static String printUnequalContext(String s1, String s2) { + + byte[] bytes1 = s1.getBytes(); + byte[] bytes2 = s2.getBytes(); + int i = 0; + for (; i < bytes1.length; i++) { + if (i > bytes2.length) + break; + + if (bytes1[i] != bytes2[i]) + break; + } + + int maxContext = 40; + int start = Math.max(0, (i - maxContext)); + int end = Math.min(i + maxContext, (Math.min(bytes1.length, bytes2.length))); + + StringBuilder sb = new StringBuilder(); + sb.append("Strings are not equal! Start of inequality is at " + i); //$NON-NLS-1$ + sb.append(". Showing " + maxContext); //$NON-NLS-1$ + sb.append(" extra characters and start and end:\n"); //$NON-NLS-1$ + sb.append("context s1: "); //$NON-NLS-1$ + sb.append(s1.substring(start, end)); + sb.append("\n"); //$NON-NLS-1$ + sb.append("context s2: "); //$NON-NLS-1$ + sb.append(s2.substring(start, end)); + sb.append("\n"); //$NON-NLS-1$ + + return sb.toString(); + } + + /** + * Formats the given number of milliseconds to a time like #h/m/s/ms/us/ns + * + * @param millis + * the number of milliseconds + * + * @return format the given number of milliseconds to a time like #h/m/s/ms/us/ns + */ + public static String formatMillisecondsDuration(final long millis) { + return formatNanoDuration(millis * 1000000L); + } + + /** + * Formats the given number of nanoseconds to a time like #h/m/s/ms/us/ns + * + * @param nanos + * the number of nanoseconds + * + * @return format the given number of nanoseconds to a time like #h/m/s/ms/us/ns + */ + public static String formatNanoDuration(final long nanos) { + if (nanos >= 3600000000000L) { + return String.format("%.0fh", (nanos / 3600000000000.0D)); //$NON-NLS-1$ + } else if (nanos >= 60000000000L) { + return String.format("%.0fm", (nanos / 60000000000.0D)); //$NON-NLS-1$ + } else if (nanos >= 1000000000L) { + return String.format("%.0fs", (nanos / 1000000000.0D)); //$NON-NLS-1$ + } else if (nanos >= 1000000L) { + return String.format("%.0fms", (nanos / 1000000.0D)); //$NON-NLS-1$ + } else if (nanos >= 1000L) { + return String.format("%.0fus", (nanos / 1000.0D)); //$NON-NLS-1$ + } else { + return nanos + "ns"; //$NON-NLS-1$ + } + } + + /** + * @see ExceptionHelper#formatException(Throwable) + */ + public static String getExceptionMessage(Throwable t) { + return ExceptionHelper.getExceptionMessage(t); + } + + /** + * @see ExceptionHelper#formatException(Throwable) + */ + public static String formatException(Throwable t) { + return ExceptionHelper.formatException(t); + } + + /** + * @see ExceptionHelper#formatExceptionMessage(Throwable) + */ + public static String formatExceptionMessage(Throwable t) { + return ExceptionHelper.formatExceptionMessage(t); + } + + /** + * Simply returns true if the value is null, or empty + * + * @param value + * the value to check + * + * @return true if the value is null, or empty + */ + public static boolean isEmpty(String value) { + return value == null || value.isEmpty(); + } + + /** + * Simply returns true if the value is neither null nor empty + * + * @param value + * the value to check + * + * @return true if the value is neither null nor empty + */ + public static boolean isNotEmpty(String value) { + return value != null && !value.isEmpty(); + } + + /** + *

+ * Parses the given string value to a boolean. This extends the default {@link Boolean#parseBoolean(String)} as it + * throws an exception if the string value is not equal to "true" or "false" being case insensitive. + *

+ * + *

+ * This additional restriction is important where false should really be caught, not any random vaue for false + *

+ * + * @param value + * the value to check + * + * @return true or false, depending on the string value + * + * @throws RuntimeException + * if the value is empty, or not equal to the case insensitive value "true" or "false" + */ + public static boolean parseBoolean(String value) throws RuntimeException { + if (isEmpty(value)) + throw new RuntimeException("Value to parse to boolean is empty! Expected case insensitive true or false"); //$NON-NLS-1$ + String tmp = value.toLowerCase(); + if (tmp.equals(Boolean.TRUE.toString())) { + return true; + } else if (tmp.equals(Boolean.FALSE.toString())) { + return false; + } else { + String msg = "Value {0} can not be parsed to boolean! Expected case insensitive true or false"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, value); + throw new RuntimeException(msg); + } + } + + public static String commaSeparated(String... values) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < values.length; i++) { + sb.append(values[i]); + if (i < values.length - 1) + sb.append(", "); //$NON-NLS-1$ + } + return sb.toString(); + } + + public static String[] splitCommaSeparated(String values) { + String[] split = values.split(","); //$NON-NLS-1$ + for (int i = 0; i < split.length; i++) { + split[i] = split[i].trim(); + } + return split; + } + + /** + * If the value parameter is empty, then a {@link #DASH} is returned, otherwise the value is returned + * + * @param value + * + * @return the non-empty value, or a {@link #DASH} + */ + public static String valueOrDash(String value) { + if (isNotEmpty(value)) + return value; + return DASH; + } + + /** + * Return a pseudo unique id which is incremented on each call. The id is initialized from the current time + * + * @return a pseudo unique id + */ + public static synchronized String getUniqueId() { + return Long.toString(getUniqueIdLong()); + } + + /** + * Return a pseudo unique id which is incremented on each call. The id is initialized from the current time + * + * @return a pseudo unique id + */ + public static synchronized long getUniqueIdLong() { + + if (uniqueId == Long.MAX_VALUE - 1) { + uniqueId = 0; + } + + uniqueId += 1; + return uniqueId; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/SystemHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/SystemHelper.java new file mode 100644 index 000000000..193d619fc --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/SystemHelper.java @@ -0,0 +1,121 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +/** + * A helper class for {@link System} methods + * + * @author Robert von Burg + */ +public class SystemHelper { + + private static final SystemHelper instance; + + static { + instance = new SystemHelper(); + } + + public static SystemHelper getInstance() { + return SystemHelper.instance; + } + + public static final String osName = System.getProperty("os.name"); //$NON-NLS-1$ + public static final String osArch = System.getProperty("os.arch"); //$NON-NLS-1$ + public static final String osVersion = System.getProperty("os.version"); //$NON-NLS-1$ + public static final String javaVendor = System.getProperty("java.vendor"); //$NON-NLS-1$ + public static final String javaVersion = System.getProperty("java.version"); //$NON-NLS-1$ + + /** + * private constructor + */ + private SystemHelper() { + // + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return SystemHelper.asString(); + } + + /** + * @see java.lang.Object#toString() + */ + public static String asString() { + StringBuilder sb = new StringBuilder(); + sb.append(SystemHelper.osName); + sb.append(StringHelper.SPACE); + sb.append(SystemHelper.osArch); + sb.append(StringHelper.SPACE); + sb.append(SystemHelper.osVersion); + sb.append(StringHelper.SPACE); + sb.append("on Java "); //$NON-NLS-1$ + sb.append(SystemHelper.javaVendor); + sb.append(" version "); //$NON-NLS-1$ + sb.append(SystemHelper.javaVersion); + return sb.toString(); + } + + public static String getUserDir() { + return System.getProperty("user.dir"); //$NON-NLS-1$ + } + + public static boolean isMacOS() { + return SystemHelper.osName.startsWith("Mac"); //$NON-NLS-1$ + } + + public static boolean isWindows() { + return SystemHelper.osName.startsWith("Win"); //$NON-NLS-1$ + } + + public static boolean isLinux() { + return SystemHelper.osName.startsWith("Lin"); //$NON-NLS-1$ + } + + public static boolean is32bit() { + return SystemHelper.osArch.equals("x86") || SystemHelper.osArch.equals("i386") //$NON-NLS-1$ //$NON-NLS-2$ + || SystemHelper.osArch.equals("i686"); //$NON-NLS-1$ + } + + public static boolean is64bit() { + return SystemHelper.osArch.equals("x86_64") || SystemHelper.osArch.equals("amd64"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public static String getMaxMemory() { + return FileHelper.humanizeFileSize(Runtime.getRuntime().maxMemory()); + } + + public static String getUsedMemory() { + return FileHelper.humanizeFileSize(Runtime.getRuntime().totalMemory()); + } + + public static String getFreeMemory() { + return FileHelper.humanizeFileSize(Runtime.getRuntime().freeMemory()); + } + + public static String getMemorySummary() { + StringBuilder sb = new StringBuilder(); + sb.append("Memory available "); //$NON-NLS-1$ + sb.append(SystemHelper.getMaxMemory()); + sb.append(" / Used: "); //$NON-NLS-1$ + sb.append(SystemHelper.getUsedMemory()); + sb.append(" / Free:"); //$NON-NLS-1$ + sb.append(SystemHelper.getFreeMemory()); + return sb.toString(); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/XmlDomSigner.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/XmlDomSigner.java new file mode 100644 index 000000000..1fd64b254 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/XmlDomSigner.java @@ -0,0 +1,264 @@ +package li.strolch.utils.helper; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyStore; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStore.TrustedCertificateEntry; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.DigestMethod; +import javax.xml.crypto.dsig.Reference; +import javax.xml.crypto.dsig.SignatureMethod; +import javax.xml.crypto.dsig.SignedInfo; +import javax.xml.crypto.dsig.Transform; +import javax.xml.crypto.dsig.XMLSignature; +import javax.xml.crypto.dsig.XMLSignatureFactory; +import javax.xml.crypto.dsig.dom.DOMSignContext; +import javax.xml.crypto.dsig.dom.DOMValidateContext; +import javax.xml.crypto.dsig.keyinfo.KeyInfo; +import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; +import javax.xml.crypto.dsig.keyinfo.X509Data; +import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; +import javax.xml.crypto.dsig.spec.TransformParameterSpec; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import li.strolch.utils.dbc.DBC; + +public class XmlDomSigner { + + private static final Logger logger = LoggerFactory.getLogger(XmlDomSigner.class); + + private KeyStore keyStore; + private String privateKeyAlias; + private String trustAlias; + + private char[] password; + + public XmlDomSigner(File keyStorePath, String privateKeyAlias, String trustAlias, char[] password) { + + DBC.PRE.assertNotEmpty("privateKeyAlias", privateKeyAlias); + DBC.PRE.assertNotEmpty("trustAlias", trustAlias); + try { + + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(new FileInputStream(keyStorePath), password); + this.keyStore = keyStore; + this.privateKeyAlias = privateKeyAlias; + this.trustAlias = trustAlias; + this.password = password; + + } catch (Exception e) { + throw new RuntimeException("Failed to read keystore " + keyStorePath); + } + } + + public void sign(Document document) throws RuntimeException { + + try { + + String id = "Signed_" + UUID.randomUUID().toString(); + Element rootElement = document.getDocumentElement(); + rootElement.setAttribute("ID", id); + rootElement.setIdAttribute("ID", true); + + // Create a DOM XMLSignatureFactory that will be used to + // generate the enveloped signature. + XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); + + // Create a Reference to the enveloped document (in this case, + // you are signing the whole document, so a URI of "" signifies + // that, and also specify the SHA1 digest algorithm and + // the ENVELOPED Transform. + List transforms = new ArrayList<>(); + transforms.add(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)); + transforms.add(fac.newTransform(CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null)); + DigestMethod digestMethod = fac.newDigestMethod(DigestMethod.SHA1, null); + Reference ref = fac.newReference("#" + id, digestMethod, transforms, null, null); + + // Create the SignedInfo. + SignedInfo signedInfo = fac.newSignedInfo( + fac.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null), // + fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), // + Collections.singletonList(ref)); + + // Load the KeyStore and get the signing key and certificate. + PrivateKeyEntry keyEntry = (PrivateKeyEntry) this.keyStore.getEntry(this.privateKeyAlias, + new KeyStore.PasswordProtection(this.password)); + PrivateKey privateKey = keyEntry.getPrivateKey(); + X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); + + // Create the KeyInfo containing the X509Data. + KeyInfoFactory kif = fac.getKeyInfoFactory(); + List x509Content = new ArrayList<>(); + + x509Content.add(cert.getSubjectX500Principal().getName()); + x509Content.add(cert); + X509Data xd = kif.newX509Data(x509Content); + KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(xd)); + + // Create a DOMSignContext and specify the RSA PrivateKey and + // location of the resulting XMLSignature's parent element. + DOMSignContext dsc = new DOMSignContext(privateKey, rootElement); + //dsc.setDefaultNamespacePrefix("samlp"); + dsc.putNamespacePrefix(XMLSignature.XMLNS, "ds"); + + // Create the XMLSignature, but don't sign it yet. + XMLSignature signature = fac.newXMLSignature(signedInfo, keyInfo); + + // Marshal, generate, and sign the enveloped signature. + signature.sign(dsc); + + } catch (Exception e) { + throw new RuntimeException("Failed to sign document", e); + } + } + + public void validate(Document doc) throws RuntimeException { + + try { + + // Create a DOM XMLSignatureFactory that will be used to + // generate the enveloped signature. + XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); + + // Find Signature element. + NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); + if (nl.getLength() == 0) { + throw new Exception("Cannot find Signature element!"); + } else if (nl.getLength() > 1) { + throw new Exception("Found multiple Signature elements!"); + } + + // Load the KeyStore and get the signing key and certificate. + TrustedCertificateEntry entry = (TrustedCertificateEntry) this.keyStore.getEntry(trustAlias, null); + PublicKey publicKey = entry.getTrustedCertificate().getPublicKey(); + + // Create a DOMValidateContext and specify a KeySelector + // and document context. + Node signatureNode = nl.item(0); + DOMValidateContext valContext = new DOMValidateContext(publicKey, signatureNode); + + // Unmarshal the XMLSignature. + valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); + XMLSignature signature = fac.unmarshalXMLSignature(valContext); + + // Validate the XMLSignature. + boolean coreValidity = signature.validate(valContext); + + // Check core validation status. + if (!coreValidity) { + logger.error("Signature failed core validation"); + boolean sv = signature.getSignatureValue().validate(valContext); + logger.error("signature validation status: " + sv); + if (!sv) { + // Check the validation status of each Reference. + Iterator i = signature.getSignedInfo().getReferences().iterator(); + for (int j = 0; i.hasNext(); j++) { + boolean refValid = ((Reference) i.next()).validate(valContext); + logger.error("ref[" + j + "] validity status: " + refValid); + } + } + throw new RuntimeException("Uh-oh validation, failed!"); + } + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + throw new RuntimeException("Failed to validate document", e); + } + } + + public static byte[] transformToBytes(Document doc) { + return transformToBytes(doc, false); + } + + public static byte[] transformToBytes(Document doc, boolean indent) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + + if (indent) { + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + transformer.transform(new DOMSource(doc), new StreamResult(out)); + return out.toByteArray(); + } catch (TransformerFactoryConfigurationError | TransformerException e) { + throw new RuntimeException("Failed to transform document to bytes!", e); + } + } + + public static void writeTo(Document doc, File file) { + try { + writeTo(doc, new FileOutputStream(file)); + } catch (FileNotFoundException e) { + throw new RuntimeException("Failed to write document to " + file.getAbsolutePath(), e); + } + } + + public static void writeTo(Document doc, OutputStream out) { + try { + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(new DOMSource(doc), new StreamResult(out)); + } catch (Exception e) { + throw new RuntimeException("Failed to write document to output stream!", e); + } + } + + public static Document parse(byte[] bytes) { + return parse(new ByteArrayInputStream(bytes)); + } + + public static Document parse(File signedXmlFile) { + try { + return parse(new FileInputStream(signedXmlFile)); + } catch (Exception e) { + throw new RuntimeException("Failed to parse signed file at " + signedXmlFile.getAbsolutePath(), e); + } + } + + public static Document parse(InputStream in) { + + Document doc; + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + doc = dbf.newDocumentBuilder().parse(in); + } catch (Exception e) { + throw new RuntimeException("Failed to parse input stream", e); + } + + return doc; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/helper/XmlHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/helper/XmlHelper.java new file mode 100644 index 000000000..b88a07aeb --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/helper/XmlHelper.java @@ -0,0 +1,284 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.text.MessageFormat; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.utils.exceptions.XmlException; + +/** + * Helper class for performing XML based tasks + * + * @author Robert von Burg + */ +public class XmlHelper { + + /** + * PROP_LINE_SEPARATOR = "line.separator" : the system property to fetch defined line separator + */ + public static final String PROP_LINE_SEPARATOR = "line.separator"; //$NON-NLS-1$ + + /** + * UNIX_LINE_SEP = "\n" : mostly we want this line separator, instead of the windows version + */ + public static final String UNIX_LINE_SEP = "\n"; //$NON-NLS-1$ + + /** + * DEFAULT_ENCODING = "utf-8" : defines the default UTF-8 encoding expected of XML files + */ + public static final String DEFAULT_ENCODING = "UTF-8"; //$NON-NLS-1$ + + private static final Logger logger = LoggerFactory.getLogger(XmlHelper.class); + + /** + * Parses an XML file on the file system and returns the resulting {@link Document} object + * + * @param xmlFile + * the {@link File} which has the path to the XML file to read + */ + public static void parseDocument(File xmlFile, DefaultHandler xmlHandler) { + + try (FileInputStream xmlFileInputStream = new FileInputStream(xmlFile);) { + + parseDocument(xmlFileInputStream, xmlHandler); + String msg = "SAX parsed file {0}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, xmlFile.getAbsolutePath())); + + } catch (IOException e) { + String msg = "Failed to parse XML file: {0} due to: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, xmlFile.getAbsolutePath(), e.getMessage()); + throw new XmlException(msg, e); + } + } + + /** + * Parses an XML file on the file system and returns the resulting {@link Document} object + * + * @param xmlFileInputStream + * the XML {@link InputStream} which is to be parsed + */ + public static void parseDocument(InputStream xmlFileInputStream, DefaultHandler xmlHandler) { + + try { + + SAXParserFactory spf = SAXParserFactory.newInstance(); + + SAXParser sp = spf.newSAXParser(); + sp.parse(xmlFileInputStream, xmlHandler); + + } catch (ParserConfigurationException e) { + throw new XmlException("Failed to initialize a SAX Parser: " + e.getMessage(), e); //$NON-NLS-1$ + } catch (SAXException e) { + throw new XmlException("The XML stream is not parseable: " + e.getMessage(), e); //$NON-NLS-1$ + } catch (IOException e) { + throw new XmlException("The XML stream not be read: " + e.getMessage(), e); //$NON-NLS-1$ + } + } + + /** + * Writes an {@link Element} to an XML file on the file system + * + * @param rootElement + * the {@link Element} to write to the file system + * @param file + * the {@link File} describing the path on the file system where the XML file should be written to + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration, or writing the element + */ + public static void writeElement(Element rootElement, File file) throws RuntimeException { + Document document = createDocument(); + document.appendChild(rootElement); + XmlHelper.writeDocument(document, file, DEFAULT_ENCODING); + } + + /** + * Writes a {@link Document} to an XML file on the file system + * + * @param document + * the {@link Document} to write to the file system + * @param file + * the {@link File} describing the path on the file system where the XML file should be written to + * @param encoding + * encoding to use to write the file + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration, or writing the element + */ + public static void writeDocument(Document document, File file) throws RuntimeException { + writeDocument(document, file, DEFAULT_ENCODING); + } + + /** + * Writes a {@link Document} to an XML file on the file system + * + * @param document + * the {@link Document} to write to the file system + * @param file + * the {@link File} describing the path on the file system where the XML file should be written to + * @param encoding + * encoding to use to write the file + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration, or writing the element + */ + public static void writeDocument(Document document, File file, String encoding) throws RuntimeException { + String msg = "Exporting document element {0} to {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, document.getNodeName(), file.getAbsolutePath()); + XmlHelper.logger.info(msg); + writeDocument(document, new StreamResult(file), encoding); + } + + /** + * Writes a {@link Document} to an XML file on the file system + * + * @param document + * the {@link Document} to write to the file system + * @param outputStream + * stream to write document to + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration, or writing the element + */ + public static void writeDocument(Document document, OutputStream outputStream) throws RuntimeException { + writeDocument(document, new StreamResult(outputStream), DEFAULT_ENCODING); + } + + /** + * Writes a {@link Document} to an XML file on the file system + * + * @param document + * the {@link Document} to write to the file system + * @param outputStream + * stream to write document to + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration, or writing the element + */ + public static String writeToString(Document document) throws RuntimeException { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writeDocument(document, new StreamResult(out), DEFAULT_ENCODING); + return out.toString(DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { + throw new XmlException("Failed to create Document: " + e.getLocalizedMessage(), e); //$NON-NLS-1$ + } + } + + /** + * Writes a {@link Document} to an XML file on the file system + * + * @param document + * the {@link Document} to write to the file system + * @param file + * the {@link File} describing the path on the file system where the XML file should be written to + * @param encoding + * encoding to use to write the file + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration, or writing the element + */ + public static void writeDocument(Document document, StreamResult streamResult, String encoding) + throws RuntimeException { + + String lineSep = System.getProperty(PROP_LINE_SEPARATOR); + try { + + String docEncoding = document.getInputEncoding(); + if (StringHelper.isEmpty(docEncoding)) { + docEncoding = encoding; + } + + if (!lineSep.equals("\n")) { //$NON-NLS-1$ + XmlHelper.logger.info("Overriding line separator to \\n"); //$NON-NLS-1$ + System.setProperty(PROP_LINE_SEPARATOR, UNIX_LINE_SEP); + } + + // Set up a transformer + TransformerFactory transfac = TransformerFactory.newInstance(); + Transformer transformer = transfac.newTransformer(); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.ENCODING, docEncoding); + transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$ + // transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t"); + + // Transform to file + Source xmlSource = new DOMSource(document); + transformer.transform(xmlSource, streamResult); + + } catch (Exception e) { + + throw new XmlException("Exception while exporting to file: " + e, e); //$NON-NLS-1$ + + } finally { + + System.setProperty(PROP_LINE_SEPARATOR, lineSep); + } + } + + /** + * Returns a new document instance + * + * @return a new document instance + * + * @throws RuntimeException + * if something went wrong while creating the XML configuration + */ + public static Document createDocument() throws RuntimeException { + try { + + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + Document document = docBuilder.newDocument(); + + return document; + + } catch (DOMException e) { + throw new XmlException("Failed to create Document: " + e.getLocalizedMessage(), e); //$NON-NLS-1$ + } catch (ParserConfigurationException e) { + throw new XmlException("Failed to create Document: " + e.getLocalizedMessage(), e); //$NON-NLS-1$ + } + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/io/FileProgressListener.java b/li.strolch.utils/src/main/java/li/strolch/utils/io/FileProgressListener.java new file mode 100644 index 000000000..cd23dae2e --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/io/FileProgressListener.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.io; + +/** + *

+ * This interface defines an API for use in situations where long running jobs notify observers of the jobs status. The + * jobs has a size which is a primitive long value e.g. the number of bytes parsed/ to be parsed in a file + *

+ * + * @author Robert von Burg + */ +public interface FileProgressListener { + + /** + * Notify the listener that the progress has begun + * + * @param percent + * percent completed + * @param position + * the position relative to the job size + * @param size + * the size of the job which is to be accomplished + */ + public void begin(int percent, long position, long size); + + /** + * Notifies the listener of incremental progress + * + * @param percent + * percent completed + * @param position + * the position relative to the job size + */ + public void progress(int percent, long position); + + /** + * Notifies the listener that the progress is completed + * + * @param percent + * the percent completed. Ideally the value would be 100, but in cases of errors it can be less + * @param position + * the position where the job finished. Ideally the value would be the same as the size given at + * {@link #begin(int, long, long)} but in case of errors it can be different + */ + public void end(int percent, long position); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/io/FileStreamProgressWatcher.java b/li.strolch.utils/src/main/java/li/strolch/utils/io/FileStreamProgressWatcher.java new file mode 100644 index 000000000..56e84a455 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/io/FileStreamProgressWatcher.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.io; + +import java.text.MessageFormat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * File stream progress monitoring thread + * + * @author Robert von Burg + */ +public class FileStreamProgressWatcher implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(FileStreamProgressWatcher.class); + private ProgressableFileInputStream inputStream; + private boolean run = false; + private FileProgressListener progressListener; + private long millis; + + /** + * @param millis + * @param progressListener + * @param inputStream + */ + public FileStreamProgressWatcher(long millis, FileProgressListener progressListener, + ProgressableFileInputStream inputStream) { + this.millis = millis; + this.progressListener = progressListener; + this.inputStream = inputStream; + } + + @Override + public void run() { + this.run = true; + this.progressListener.begin(this.inputStream.getPercentComplete(), this.inputStream.getBytesRead(), + this.inputStream.getFileSize()); + + while (this.run) { + try { + int percentComplete = this.inputStream.getPercentComplete(); + if (this.inputStream.isClosed()) { + logger.info(MessageFormat.format("Input Stream is closed at: {0}%", percentComplete)); //$NON-NLS-1$ + this.run = false; + this.progressListener.end(percentComplete, this.inputStream.getBytesRead()); + } else if (percentComplete < 100) { + this.progressListener.progress(percentComplete, this.inputStream.getBytesRead()); + } else if (percentComplete >= 100) { + this.run = false; + this.progressListener.end(percentComplete, this.inputStream.getBytesRead()); + } + + if (this.run) + Thread.sleep(this.millis); + + } catch (InterruptedException e) { + this.run = false; + int percentComplete = this.inputStream.getPercentComplete(); + if (percentComplete != 100) + logger.info(MessageFormat.format("Work stopped: {0}", e.getLocalizedMessage())); //$NON-NLS-1$ + this.progressListener.end(percentComplete, this.inputStream.getBytesRead()); + } catch (Exception e) { + logger.error(e.getMessage(), e); + this.run = false; + int percentComplete = this.inputStream.getPercentComplete(); + this.progressListener.end(percentComplete, Long.MAX_VALUE); + } + } + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/io/LoggingFileProgressListener.java b/li.strolch.utils/src/main/java/li/strolch/utils/io/LoggingFileProgressListener.java new file mode 100644 index 000000000..e9e361292 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/io/LoggingFileProgressListener.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.io; + +import java.text.MessageFormat; + +import org.slf4j.Logger; + +import li.strolch.utils.helper.FileHelper; + +/** + * @author Robert von Burg + */ +public class LoggingFileProgressListener implements FileProgressListener { + + private final Logger logger; + private final String name; + + /** + * @param logger + * @param name + */ + public LoggingFileProgressListener(Logger logger, String name) { + this.logger = logger; + this.name = name; + } + + @Override + public void begin(int percent, long position, long size) { + String msg = "Starting to read {0} {1} of {2} ({3}%)"; //$NON-NLS-1$ + log(MessageFormat.format(msg, this.name, position, FileHelper.humanizeFileSize(size), percent)); + } + + @Override + public void progress(int percent, long position) { + String msg = "Read {0}% of {1} at position {2}"; //$NON-NLS-1$ + log(MessageFormat.format(msg, percent, this.name, FileHelper.humanizeFileSize(position))); + } + + @Override + public void end(int percent, long position) { + String msg = "Finished reading {0} at position {1} ({2}%)"; //$NON-NLS-1$ + log(MessageFormat.format(msg, this.name, FileHelper.humanizeFileSize(position), percent)); + } + + private void log(String msg) { + this.logger.info(msg); + } + +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/io/ProgressableFileInputStream.java b/li.strolch.utils/src/main/java/li/strolch/utils/io/ProgressableFileInputStream.java new file mode 100644 index 000000000..45513bd25 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/io/ProgressableFileInputStream.java @@ -0,0 +1,161 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.io; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + *

+ * This sub class of {@link FileInputStream} allows to follow the currently read bytes of a {@link File}. In conjunction + * with a {@link Thread} and a {@link FileProgressListener} it is possible to track the progress of a long running job + * on bigger files + *

+ * + * @author Robert von Burg + */ +public class ProgressableFileInputStream extends FileInputStream { + + private volatile long fileSize; + private volatile long bytesRead; + private volatile boolean closed; + + /** + * Constructs a normal {@link FileInputStream} with the given {@link File} + * + * @param file + * the file to read + * @throws FileNotFoundException + * thrown if the {@link File} does not exist + */ + public ProgressableFileInputStream(File file) throws FileNotFoundException { + super(file); + this.fileSize = file.length(); + } + + /** + * @see java.io.FileInputStream#read() + */ + @Override + public int read() throws IOException { + synchronized (this) { + this.bytesRead++; + } + return super.read(); + } + + /** + * @see java.io.FileInputStream#read(byte[], int, int) + */ + @Override + public int read(byte[] b, int off, int len) throws IOException { + int read = super.read(b, off, len); + if (read != -1) { + synchronized (this) { + this.bytesRead += read; + } + } + return read; + } + + /** + * @see java.io.FileInputStream#read(byte[]) + */ + @Override + public int read(byte[] b) throws IOException { + int read = super.read(b); + if (read != -1) { + synchronized (this) { + this.bytesRead += read; + } + } + return read; + } + + /** + * @see java.io.FileInputStream#skip(long) + */ + @Override + public long skip(long n) throws IOException { + long skip = super.skip(n); + if (skip != -1) { + synchronized (this) { + this.bytesRead += skip; + } + } + return skip; + } + + /** + * @see java.io.FileInputStream#close() + */ + @Override + public void close() throws IOException { + this.closed = true; + super.close(); + } + + /** + * Returns the size of the file being read + * + * @return the size of the file being read + */ + public long getFileSize() { + return this.fileSize; + } + + /** + * Returns the number of bytes already read + * + * @return the number of bytes already read + */ + public long getBytesRead() { + synchronized (this) { + if (this.bytesRead > this.fileSize) + this.bytesRead = this.fileSize; + return this.bytesRead; + } + } + + /** + * Returns the percent read of the file + * + * @return the percentage complete of the process + */ + public int getPercentComplete() { + + long currentRead; + synchronized (this) { + if (this.bytesRead > this.fileSize) + this.bytesRead = this.fileSize; + currentRead = this.bytesRead; + } + + double read = (100.0d / this.fileSize * currentRead); + return (int) Math.ceil(read); + } + + /** + * Returns true if {@link #close()} was called, false otherwise + * + * @return the closed + */ + public boolean isClosed() { + return this.closed; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DateFormat.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DateFormat.java new file mode 100644 index 000000000..25a834fa1 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DateFormat.java @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +import java.util.Date; + +/** + * Interface for date formatting + * + * Martin Smock + */ +public interface DateFormat { + + /** + * format a long to string + * + * @param timepoint + * @return the formatted string of the long value + */ + public String format(long timepoint); + + /** + * format a Date to string + * + * @param date + * @return the formatted string of the long value + */ + public String format(Date date); + + /** + * parse a string to long + * + * @param s + * @return the value parsed + */ + public long parseLong(String s); + + /** + * parse a string to Date + * + * @param s + * @return the value parsed + */ + public Date parse(String s); +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java new file mode 100644 index 000000000..dbda3b20d --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +/** + * Interface for duration formatting + * + * Martin Smock + */ +public interface DurationFormat { + + /** + * format a long to string + * + * @param l + * @return formatted string if the long argument + */ + public String format(long l); + + /** + * parse a string to long + * + * @param s + * @return the long value parsed + */ + public long parse(String s); + +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java new file mode 100644 index 000000000..50bb21e49 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java @@ -0,0 +1,142 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +import java.util.Date; + +/** + * This interface defines methods for formatting values for UI representation and also defines factory methods for + * formatters for parsing and formatting duration and date values + * + * Martin Smock + */ +public interface FormatFactory { + + /** + * return the formatter for dates + * + * @return {@link DurationFormat} + */ + public DateFormat getDateFormat(); + + /** + * return the formatter for durations + * + * @return {@link DurationFormat} + */ + public DurationFormat getDurationFormat(); + + /** + * return the formatter for work time + * + * @return {@link WorktimeFormat} + */ + public WorktimeFormat getWorktimeFormat(); + + /** + * the date format used in xml import and export + * + * @return {@link DateFormat} + */ + public DateFormat getXmlDateFormat(); + + /** + * the duration format used in xml import and export + * + * @return {@link DurationFormat} + */ + public DurationFormat getXmlDurationFormat(); + + /** + * Formats a date using {@link #getDateFormat()} + * + * @param date + * the date to format to string + * + * @return String representation of the date + */ + public String formatDate(Date date); + + /** + * Formats a long as date using {@link #getDateFormat()} + * + * @param date + * the date to format to string + * + * @return String representation of the date + */ + public String formatDate(long date); + + /** + * Formats a duration using {@link #getDateFormat()} + * + * @param duration + * the duration to format to string + * + * @return String representation of the duration + */ + public String formatDuration(long duration); + + /** + * Formats a work time duration using {@link #getDateFormat()} + * + * @param worktime + * the work time duration to format to string + * + * @return String representation of the work time duration + */ + public String formatWorktime(long worktime); + + /** + * Formats a floating point number to have the configured number of decimals + * + * @param value + * the value to format + * + * @return the floating point formatted as a string + */ + public String formatFloat(double value); + + /** + * Parses a date using {@link #getDateFormat()} + * + * @param date + * the string to parse to date + * + * @return the date + */ + public Date parseDate(String date); + + /** + * Parses a duration using {@link #getDateFormat()} + * + * @param duration + * the string to parse to duration + * + * @return the duration + */ + public long parseDuration(String duration); + + /** + * Parses a work time duration using {@link #getDateFormat()} + * + * @param worktime + * the string duration to parse to work time + * + * @return the work time + */ + public long parseWorktime(String worktime); +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601.java new file mode 100644 index 000000000..fe06e5761 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601.java @@ -0,0 +1,297 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +import java.text.DecimalFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.StringHelper; + +/** + * @author Martin Smock + */ +@SuppressWarnings("nls") +public class ISO8601 implements DateFormat { + + private static final Logger logger = LoggerFactory.getLogger(ISO8601.class); + + //misc. numeric formats used in formatting + private DecimalFormat xxFormat = new DecimalFormat("00"); + private DecimalFormat xxxFormat = new DecimalFormat("000"); + private DecimalFormat xxxxFormat = new DecimalFormat("0000"); + + /** + * + */ + private Calendar parseToCalendar(String text) { + + // check optional leading sign + char sign; + int start; + if (text.startsWith("-")) { + sign = '-'; + start = 1; + } else if (text.startsWith("+")) { + sign = '+'; + start = 1; + } else { + sign = '+'; // no sign specified, implied '+' + start = 0; + } + + /** + * format of the string is: YYYY-MM-DDThh:mm:ss.SSSTZD + */ + int year, month, day, hour, min, sec, millisec; + String timeZone; + try { + + // year (YYYY) + year = Integer.parseInt(text.substring(start, start + 4)); + start += 4; + // delimiter '-' + if (text.charAt(start) != '-') { + return null; + } + start++; + + // month (MM) + month = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter '-' + if (text.charAt(start) != '-') { + return null; + } + start++; + + // day (DD) + day = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter 'T' + if (text.charAt(start) != 'T') { + return null; + } + start++; + + // hour (hh) + hour = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter ':' + if (text.charAt(start) != ':') { + return null; + } + start++; + + // minute (mm) + min = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter ':' + if (text.charAt(start) != ':') { + return null; + } + start++; + + // second (ss) + sec = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + + // delimiter '.' + if (text.charAt(start) == '.') { + start++; + // millisecond (SSS) + millisec = Integer.parseInt(text.substring(start, start + 3)); + start += 3; + } else { + millisec = 0; + } + + if (text.charAt(start) == '+' || text.charAt(start) == '-') { + timeZone = "GMT" + text.substring(start); + } else if (text.substring(start).equals("Z")) { + timeZone = "GMT"; + } else { + return null; + } + + } catch (IndexOutOfBoundsException e) { + return null; + } catch (NumberFormatException e) { + return null; + } + + TimeZone tz = TimeZone.getTimeZone(timeZone); + if (!tz.getID().equals(timeZone)) { + // invalid time zone + return null; + } + + // create Calendar + Calendar cal = Calendar.getInstance(tz); + cal.setLenient(false); + + if (sign == '-' || year == 0) { + // + cal.set(Calendar.YEAR, year + 1); + cal.set(Calendar.ERA, GregorianCalendar.BC); + } else { + cal.set(Calendar.YEAR, year); + cal.set(Calendar.ERA, GregorianCalendar.AD); + } + + // + cal.set(Calendar.MONTH, month - 1); + cal.set(Calendar.DAY_OF_MONTH, day); + cal.set(Calendar.HOUR_OF_DAY, hour); + cal.set(Calendar.MINUTE, min); + cal.set(Calendar.SECOND, sec); + cal.set(Calendar.MILLISECOND, millisec); + + try { + cal.getTime(); + } catch (IllegalArgumentException e) { + return null; + } + + return cal; + } + + /** + * + */ + private String format(Calendar cal) { + + if (cal == null) { + throw new IllegalArgumentException("argument can not be null"); + } + + // determine era and adjust year if necessary + int year = cal.get(Calendar.YEAR); + if (cal.isSet(Calendar.ERA) && cal.get(Calendar.ERA) == GregorianCalendar.BC) { + /** + * calculate year using astronomical system: year n BCE => astronomical year -n + 1 + */ + year = 0 - year + 1; + } + + /** + * format of date/time string is: YYYY-MM-DDThh:mm:ss.SSSTZD + */ + StringBuilder sWriter = new StringBuilder(); + sWriter.append(this.xxxxFormat.format(year)); + sWriter.append('-'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.MONTH) + 1)); + sWriter.append('-'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.DAY_OF_MONTH))); + sWriter.append('T'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.HOUR_OF_DAY))); + sWriter.append(':'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.MINUTE))); + sWriter.append(':'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.SECOND))); + sWriter.append('.'); + sWriter.append(this.xxxFormat.format(cal.get(Calendar.MILLISECOND))); + TimeZone tz = cal.getTimeZone(); + + int offset = tz.getOffset(cal.getTimeInMillis()); + if (offset != 0) { + int hours = Math.abs((offset / (60 * 1000)) / 60); + int minutes = Math.abs((offset / (60 * 1000)) % 60); + sWriter.append(offset < 0 ? '-' : '+'); + sWriter.append(this.xxFormat.format(hours)); + sWriter.append(':'); + sWriter.append(this.xxFormat.format(minutes)); + } else { + sWriter.append('Z'); + } + return sWriter.toString(); + } + + @Override + public String format(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return format(cal); + } + + /** + * added by msmock convert a long to ISO8601 + * + * @param timePoint + * @return time point as ISO8601 String + */ + @Override + public String format(long timePoint) { + + if (timePoint == Long.MAX_VALUE || timePoint == Long.MIN_VALUE) { + return "-"; + } + + // else + try { + Date date = new Date(); + date.setTime(timePoint); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return format(cal); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return null; + } + } + + @Override + public long parseLong(String s) { + return parse(s).getTime(); + } + + /** + * parse ISO8601 date to long + * + * @param s + * the string to parse + * @return time point as long + * @throws NumberFormatException + */ + @Override + public Date parse(String s) { + + if (StringHelper.isEmpty(s)) { + String msg = "An empty value can not pe parsed to a date!"; + throw new IllegalArgumentException(msg); + } + + if (s.equals("-")) { + Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.setTimeZone(TimeZone.getTimeZone("GMT0")); + return cal.getTime(); + } + + Calendar cal = parseToCalendar(s); + if (cal != null) { + return cal.getTime(); + } + + String msg = "Input string '" + s + "' cannot be parsed to date."; + throw new IllegalArgumentException(msg); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java new file mode 100644 index 000000000..dffb65b59 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java @@ -0,0 +1,264 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +/** + *

+ * Duration is defined as a duration of time, as specified in ISO 8601, Section 5.5.3.2. Its lexical representation is + * the ISO 8601 extended format: PnYnMnDnTnHnMnS + *

+ *
    + *
  • The "P" (period) is required
  • + *
  • "n" represents a positive number
  • + *
  • years is (Y)
  • + *
  • months is (M)
  • + *
  • days is (D)
  • + *
  • time separator is (T), required if any lower terms are given
  • + *
  • hours is (H)
  • + *
  • minutes is (M)
  • + *
  • seconds is (S)
  • + *
+ *

+ * An optional preceding minus sign ("-") is also allowed to indicate a negative duration. If the sign is omitted then a + * positive duration is assumed. For example: is a 2 hour, 5 minute, and + * 2.37 second duration + *

+ *

+ * Remark: since a duration of a day may be measured in hours may vary from 23 an 25 a duration day unit doesn't + * have a meaning, if we do not know either the start or the end, we restrict ourself to measure a duration in hours, + * minutes and seconds + *

+ * + * @author Martin Smock + * @author Michael Gatto (reimplementation using enum) + */ +@SuppressWarnings("nls") +public class ISO8601Duration implements DurationFormat { + + /** + * The time representations available, as enum, with the associated millis. + * + * @author gattom + */ + public enum TimeDuration { + SECOND(1000, 'S'), + MINUTE(60 * SECOND.duration(), 'M'), + HOUR(60 * MINUTE.duration(), 'H'), + DAY(24 * HOUR.duration(), 'D'), + WEEK(7 * DAY.duration(), 'W'), + MONTH(30 * DAY.duration(), 'M'), + YEAR(12 * MONTH.duration(), 'Y'); + + final long millis; + final char isoChar; + + TimeDuration(long milli, char isorep) { + this.millis = milli; + this.isoChar = isorep; + } + + public long duration() { + return this.millis; + } + + public static TimeDuration getTimeDurationFor(String isostring, int unitIndex) { + char duration = isostring.charAt(unitIndex); + switch (duration) { + case 'S': + if (isostring.substring(0, unitIndex).contains("T")) + return SECOND; + throw new NumberFormatException( + duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1S)"); + case 'H': + if (isostring.substring(0, unitIndex).contains("T")) + return HOUR; + throw new NumberFormatException( + duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1H)"); + case 'D': + return DAY; + case 'W': + return WEEK; + case 'Y': + return YEAR; + case 'M': + if (isostring.substring(0, unitIndex).contains("T")) + return MINUTE; + return MONTH; + default: + throw new NumberFormatException(duration + " is not a valid unit of time in ISO8601"); + } + } + } + + /** + * check if c is a number char including the decimal decimal dot (.) + * + * @param c + * the character to check + * @return boolean return true if the given char is a number or a decimal dot (.), false otherwise + */ + private static boolean isNumber(char c) { + + boolean isNumber = Character.isDigit(c) || (c == '.'); + return isNumber; + + } + + /** + * Parses the given string to a pseudo ISO 8601 duration + * + * @param s + * the string to be parsed to a duration which must be coded as a ISO8601 value + * @return long the time value which represents the duration + */ + @Override + public long parse(String s) { + + long newResult = 0; + + // throw exception, if the string is not of length > 2 + if (s == null || s.length() < 3) + throw new NumberFormatException(s + " cannot be parsed to ISO 8601 Duration"); + + char p = s.charAt(0); + + // the first char must be a P for ISO8601 duration + if (p != 'P') + throw new NumberFormatException(s + " cannot be parsed to ISO 8601 Duration"); + + int newposition = 1; + do { + if (s.charAt(newposition) == 'T') { + // skip the separator specifying where the time starts. + newposition++; + } + + // read the string representing the numeric value + String val = parseNumber(newposition, s); + double numVal = Double.parseDouble(val); + newposition += val.length(); + + // get the time unit + TimeDuration unit = TimeDuration.getTimeDurationFor(s, newposition); + + // skip the time duration character + newposition++; + + // increment the value. + newResult += unit.duration() * numVal; + + } while (newposition < s.length()); + + return newResult; + } + + /** + * Return the substring of s starting at index i (in s) that contains a numeric string. + * + * @param index + * The start index in string s + * @param s + * The string to analyze + * @return the substring containing the numeric portion of s starting at index i. + */ + private String parseNumber(int index, String s) { + int i = index; + int start = i; + while (i < s.length()) { + if (!isNumber(s.charAt(i))) + break; + i++; + } + String substring = s.substring(start, i); + return substring; + } + + /** + * Format the given time duration unit into the string buffer. This function displays the given duration in units of + * the given unit, and returns the remainder. + *

+ * Thus, a duration of 86401000 (one day and one second) will add the representation of one day if unit is DAY (1D) + * and return 1000 as the remainder with respect of this unit. If the given unit is HOUR, then this function adds + * 24H to the {@link StringBuilder}, and returns 1000 as the remainder. + * + * @param sb + * The {@link StringBuilder} to add the given duration with the right unit + * @param duration + * The duration to add + * @param unit + * The unit of this duration + * @return The remainder of the given duration, modulo the time unit. + */ + private long formatTimeDuration(StringBuilder sb, long duration, TimeDuration unit) { + + long remainder = duration; + if (unit.equals(TimeDuration.SECOND) || remainder >= unit.duration()) { + + long quantity = remainder / unit.duration(); + remainder = remainder % unit.duration(); + sb.append(quantity); + + if (unit.equals(TimeDuration.SECOND)) { + long millis = remainder; + if (millis == 0) { + // to not have the decimal point + } else if (millis > 99) { + sb.append("." + millis); + } else if (millis > 9) { + sb.append(".0" + millis); + } else { + sb.append(".00" + millis); + } + } + + sb.append(unit.isoChar); + } + + return remainder; + } + + /** + * Formats the given time duration to a pseudo ISO 8601 duration string + * + * @param duration + * @return String the duration formatted as a ISO8601 duration string + */ + @Override + public String format(long duration) { + + // XXX this is a preliminary help to solve the situation where this method sometimes returns P + if (duration < 0l) + throw new RuntimeException("A duration can not be negative!"); + + if (duration == 0l) + return "P0D"; + + StringBuilder sb = new StringBuilder(); + sb.append('P'); + + long remainder = formatTimeDuration(sb, duration, TimeDuration.YEAR); + remainder = formatTimeDuration(sb, remainder, TimeDuration.MONTH); + remainder = formatTimeDuration(sb, remainder, TimeDuration.DAY); + if (remainder > 0) { + sb.append('T'); + remainder = formatTimeDuration(sb, remainder, TimeDuration.HOUR); + remainder = formatTimeDuration(sb, remainder, TimeDuration.MINUTE); + remainder = formatTimeDuration(sb, remainder, TimeDuration.SECOND); + } + return sb.toString(); + } + +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java new file mode 100644 index 000000000..cf9f24116 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java @@ -0,0 +1,109 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +import java.util.Date; + +import li.strolch.utils.helper.MathHelper; + +/** + * Default factory for date formats used for serialization. + * + * @author Martin Smock + */ +public class ISO8601FormatFactory implements FormatFactory { + + private static ISO8601FormatFactory instance = new ISO8601FormatFactory(); + + /** + * the singleton constructor + */ + private ISO8601FormatFactory() { + // singleton + } + + /** + * @return the instance + */ + public static ISO8601FormatFactory getInstance() { + return instance; + } + + @Override + public ISO8601 getDateFormat() { + return new ISO8601(); + } + + @Override + public ISO8601Duration getDurationFormat() { + return new ISO8601Duration(); + } + + @Override + public ISO8601Worktime getWorktimeFormat() { + return new ISO8601Worktime(); + } + + @Override + public ISO8601 getXmlDateFormat() { + return new ISO8601(); + } + + @Override + public ISO8601Duration getXmlDurationFormat() { + return new ISO8601Duration(); + } + + @Override + public String formatDate(Date date) { + return getDateFormat().format(date); + } + + @Override + public String formatDate(long date) { + return getDateFormat().format(date); + } + + @Override + public String formatDuration(long duration) { + return getDurationFormat().format(duration); + } + + @Override + public String formatWorktime(long worktime) { + return getDurationFormat().format(worktime); + } + + @Override + public String formatFloat(double value) { + return Double.toString(MathHelper.toPrecision(value)); + } + + @Override + public Date parseDate(String date) { + return getDateFormat().parse(date); + } + + @Override + public long parseDuration(String duration) { + return getDurationFormat().parse(duration); + } + + @Override + public long parseWorktime(String worktime) { + return getDurationFormat().parse(worktime); + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java new file mode 100644 index 000000000..5f233b7d4 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java @@ -0,0 +1,237 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +/** + *

+ * Duration is defined as a duration of time, as specified in ISO 8601, Section 5.5.3.2. Its lexical representation is + * the ISO 8601 extended format: PnYnMnDnTnHnMnS + *

+ *
    + *
  • The "P" (period) is required
  • + *
  • "n" represents a positive number
  • + *
  • years is (Y)
  • + *
  • months is (M)
  • + *
  • days is (D)
  • + *
  • time separator is (T), required if any lower terms are given
  • + *
  • hours is (H)
  • + *
  • minutes is (M)
  • + *
  • seconds is (S)
  • + *
+ *

+ * An optional preceding minus sign ("-") is also allowed to indicate a negative duration. If the sign is omitted then a + * positive duration is assumed. For example: is a 2 hour, 5 minute, and + * 2.37 second duration + *

+ *

+ * Remark: since a duration of a day may be measured in hours may vary from 23 an 25 a duration day unit doesn't + * have a meaning, if we do not know either the start or the end, we restrict ourself to measure a duration in hours, + * minutes and seconds + *

+ * + * @author Martin Smock + * @author Michael Gatto (reimplementation using enum) + */ +@SuppressWarnings("nls") +public class ISO8601Worktime implements WorktimeFormat { + + /** + * The time representations available, as enum, with the associated millis. + * + * @author gattom + */ + public enum TimeDuration { + + SECOND(1000, 'S'), MINUTE(60 * SECOND.duration(), 'M'), HOUR(60 * MINUTE.duration(), 'H'); + + final long millis; + final char isoChar; + + TimeDuration(long milli, char isorep) { + this.millis = milli; + this.isoChar = isorep; + } + + public long duration() { + return this.millis; + } + + public static TimeDuration getTimeDurationFor(String isostring, int unitIndex) { + char duration = isostring.charAt(unitIndex); + switch (duration) { + case 'S': + if (isostring.substring(0, unitIndex).contains("T")) + return SECOND; + throw new NumberFormatException( + duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1S)"); + case 'H': + if (isostring.substring(0, unitIndex).contains("T")) + return HOUR; + throw new NumberFormatException( + duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1H)"); + case 'M': + return MINUTE; + default: + throw new NumberFormatException(duration + " is not a valid unit of time in ISO8601"); + } + } + + } + + /** + * check if c is a number char including the decimal decimal dot (.) + * + * @param c + * the character to check + * @return boolean return true if the given char is a number or a decimal dot (.), false otherwise + */ + private static boolean isNumber(char c) { + boolean isNumber = Character.isDigit(c) || (c == '.'); + return isNumber; + } + + /** + * Parses the given string to a pseudo ISO 8601 duration + * + * @param s + * the string to be parsed to a duration which must be coded as a ISO8601 value + * @return long the time value which represents the duration + */ + @Override + public long parse(String s) { + + long newResult = 0; + + // throw exception, if the string is not of length > 2 + if (s.length() < 3) + throw new NumberFormatException(s + " cannot be parsed to ISA 8601 Duration"); + + char p = s.charAt(0); + + if (p == 'P') { + int newposition = 1; + do { + if (s.charAt(newposition) == 'T') { + // skip the separator specifying where the time starts. + newposition++; + } + // read the string representing the numeric value + String val = parseNumber(newposition, s); + double numVal = Double.parseDouble(val); + newposition += val.length(); + // get the time unit + TimeDuration unit = TimeDuration.getTimeDurationFor(s, newposition); + // skip the time duration character + newposition++; + // increment the value. + newResult += unit.duration() * numVal; + } while (newposition < s.length()); + + return newResult; + } + + throw new NumberFormatException(s + " cannot be parsed to ISO 8601 Duration"); + } + + /** + * Return the substring of s starting at index i (in s) that contains a numeric string. + * + * @param index + * The start index in string s + * @param s + * The string to analyze + * @return the substring containing the numeric portion of s starting at index i. + */ + private String parseNumber(int index, String s) { + int i = index; + int start = i; + while (i < s.length()) { + if (!isNumber(s.charAt(i))) + break; + i++; + } + String substring = s.substring(start, i); + return substring; + } + + /** + * Format the given time duration unit into the string buffer. This function displays the given duration in units of + * the given unit, and returns the remainder. + *

+ * Thus, a duration of 86401000 (one day and one second) will add the representation of one day if unit is DAY (1D) + * and return 1000 as the remainder with respect of this unit. If the given unit is HOUR, then this function adds + * 24H to the {@link StringBuilder}, and returns 1000 as the remainder. + * + * @param sb + * The {@link StringBuilder} to add the given duration with the right unit + * @param duration + * The duration to add + * @param unit + * The unit of this duration + * @return The remainder of the given duration, modulo the time unit. + */ + private long formatTimeDuration(StringBuilder sb, long duration, TimeDuration unit) { + + long remainder = duration; + + if (unit.equals(TimeDuration.SECOND) || remainder >= unit.duration()) { + + long quantity = remainder / unit.duration(); + remainder = remainder % unit.duration(); + sb.append(quantity); + + if (unit.equals(TimeDuration.SECOND)) { + + long millis = remainder; + if (millis == 0) { + // to not have the decimal point + } else if (millis > 99) { + sb.append("." + millis); + } else if (millis > 9) { + sb.append(".0" + millis); + } else { + sb.append(".00" + millis); + } + } + + sb.append(unit.isoChar); + } + return remainder; + } + + /** + * Formats the given time duration to a pseudo ISO 8601 duration string + * + * @param duration + * @return String the duration formatted as a ISO8601 duration string + */ + @Override + public String format(long duration) { + + if (duration == 0) + return "PT0S"; + + StringBuilder sb = new StringBuilder(); + sb.append('P'); + sb.append('T'); + long remainder = formatTimeDuration(sb, duration, TimeDuration.HOUR); + remainder = formatTimeDuration(sb, remainder, TimeDuration.MINUTE); + remainder = formatTimeDuration(sb, remainder, TimeDuration.SECOND); + + return sb.toString(); + } + +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/WorktimeFormat.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/WorktimeFormat.java new file mode 100644 index 000000000..48c1e0f6f --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/WorktimeFormat.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.iso8601; + +/** + * interface for the worktime format + * + * @author Martin Smock + */ +public interface WorktimeFormat { + + /** + * format a long to string + * + * @param l + * @return formatted string if the long argument + */ + public String format(long l); + + /** + * parse a string to long + * + * @param s + * @return the long value parsed + */ + public long parse(String s); + +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectCache.java b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectCache.java new file mode 100644 index 000000000..f1d25d897 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectCache.java @@ -0,0 +1,149 @@ +/* + * Copyright 2013 Michael Gatto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.objectfilter; + +import java.text.MessageFormat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is a cache for objects whose operations (additions, modifications, removals) are first collected and then + * "deployed" in one go. + *

+ * Thus, this class keeps: + *

    + *
  • An ID of the object, such that it can be referenced externally. + *
  • A key for an object, which keeps the object's type.
  • + *
  • A reference to the current state of the object
  • + *
  • An identifier of the operation that needs to be performed on this
  • + *
+ *

+ * + * @author Michael Gatto + * @author Robert von Burg + */ +public class ObjectCache { + + private final static Logger logger = LoggerFactory.getLogger(ObjectCache.class); + + /** + * UNSET Marker to determine if ids have not been set. + */ + public static final long UNSET = 0; + + /** + * id The unique ID of this object in this session + */ + private final long id; + + /** + * key The key defining who's registered for this object's state + */ + private final String key; + + /** + * operation The operation that has occurred on this object. + */ + private Operation operation; + + /** + * object The object that shall be cached + */ + private Object object; + + /** + * @param id + * @param key + * @param object + * @param operation + */ + @SuppressWarnings("nls") + public ObjectCache(long id, String key, Object object, Operation operation) { + + this.id = id; + this.key = key; + this.object = object; + this.operation = operation; + + if (logger.isDebugEnabled()) { + StringBuilder sb = new StringBuilder(); + sb.append("Instanciated Cache: ID"); + sb.append(this.id); + sb.append(" / "); + sb.append(key); + sb.append(" OP: "); + sb.append(this.operation); + sb.append(" / "); + sb.append(object.toString()); + logger.debug(sb.toString()); + } + } + + /** + * Set the new object version of this cache. + * + * @param object + */ + public void setObject(Object object) { + if (logger.isDebugEnabled()) { + logger.debug(MessageFormat.format("Updating ID {0} to value {1}", this.id, object.toString())); //$NON-NLS-1$ + } + this.object = object; + } + + /** + * Change the operation to execute for this object. + * + * @param newOperation + */ + public void setOperation(Operation newOperation) { + if (logger.isDebugEnabled()) { + String msg = "Updating Operation of ID {0} from {1} to {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, this.id, this.operation, newOperation); + logger.debug(msg); + } + this.operation = newOperation; + } + + /** + * @return the id + */ + public long getId() { + return this.id; + } + + /** + * @return the key + */ + public String getKey() { + return this.key; + } + + /** + * @return the operation + */ + public Operation getOperation() { + return this.operation; + } + + /** + * @return the object + */ + public Object getObject() { + return this.object; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java new file mode 100644 index 000000000..b42c06139 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java @@ -0,0 +1,693 @@ +/* + * Copyright 2013 Michael Gatto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.objectfilter; + +import java.text.MessageFormat; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class implements a filter where modifications to an object are collected, and only the most recent action and + * version of the object is returned. + *

+ * In its current implementation, any instance of an object may "live" in the cache registered only under one single + * key. + *

+ *

+ * The rules of the cache are defined as follows. The top row represents the state of the cache for an object, given in + * version O1. Here, "N/A" symbolizes that the object is not yet present in the cache or, if it is a result of an + * operation, that it is removed from the cache. Each other row symbolizes the next action that is performed on an + * object, with the cell containing the "final" action for this object with the version of the object to be retained. + * Err! symbolize incorrect sequences of events that cause an exception. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Action \ State in CacheN/AAdd(01)Update(O1)Remove(O1)
Add (O2)Add(O2)Err!Err!Update(O2)
Update (O2)Update(O2)Add(O2)Update(O2)Err!
Remove (O2)Remove(O2)N/ARemove(O2)Err!
+ * + * @author Michael Gatto (initial version) + * @author Robert von Burg (minor modifications, refactorings) + */ +public class ObjectFilter { + + private final static Logger logger = LoggerFactory.getLogger(ObjectFilter.class); + + private static long id = ObjectCache.UNSET; + + private final Map cache; + private final Set keySet; + + /** + * Default constructor initializing the filter + */ + public ObjectFilter() { + this.cache = new HashMap<>(); + this.keySet = new HashSet<>(); + } + + /** + * Register, under the given key, the addition of the given object. + *

+ * This is the single point where the updating logic is applied for the cache in case of addition. The logic is: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Action\State in CacheN/AAdd(01)Update(O1)Remove(O1)
Add (O2)Add(O2)Err!Err!Update(O2)
+ * + * @param key + * the key to register the object with + * @param objectToAdd + * The object for which addition shall be registered. + */ + public void add(String key, Object objectToAdd) { + + if (ObjectFilter.logger.isDebugEnabled()) + ObjectFilter.logger.debug(MessageFormat.format("add object {0} with key {1}", objectToAdd, key)); //$NON-NLS-1$ + + // BEWARE: you fix a bug here, be sure to update BOTH tables on the logic. + ObjectCache cached = this.cache.get(objectToAdd); + if (cached == null) { + + // The object has not yet been added to the cache. + // Hence, we add it now, with the ADD operation. + ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectToAdd, Operation.ADD); + this.cache.put(objectToAdd, cacheObj); + + } else { + + String existingKey = cached.getKey(); + if (!existingKey.equals(key)) { + String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$ + throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id), + Operation.ADD.toString(), existingKey, key, objectToAdd.toString())); + } + + // The object is in cache: update the version as required, keeping in mind that most + // of the cases here will be mistakes... + Operation op = cached.getOperation(); + switch (op) { + case ADD: + throw new IllegalStateException("Stale State exception: Invalid + after +"); //$NON-NLS-1$ + case MODIFY: + throw new IllegalStateException("Stale State exception: Invalid + after +="); //$NON-NLS-1$ + case REMOVE: + // replace key if necessary + replaceKey(cached.getObject(), objectToAdd); + + // update operation's object + cached.setObject(objectToAdd); + cached.setOperation(Operation.MODIFY); + break; + default: + throw new IllegalStateException("Stale State exception: Unhandled state " + op); //$NON-NLS-1$ + } // switch + }// else of object not in cache + + // register the key + this.keySet.add(key); + } + + private void replaceKey(Object oldObject, Object newObject) { + if (oldObject != newObject) { + if (ObjectFilter.logger.isDebugEnabled()) { + String msg = "Replacing key for object as they are not the same reference: old: {0} / new: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, oldObject, newObject); + ObjectFilter.logger.warn(msg); + } + ObjectCache objectCache = this.cache.remove(oldObject); + this.cache.put(newObject, objectCache); + } + } + + /** + * Register, under the given key, the update of the given object. *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Action \ State in CacheN/AAdd(01)Update(O1)Remove(O1)
Update (O2)Update(O2)Add(O2)Update(O2)Err!
+ * + * @param key + * the key to register the object with + * @param objectToUpdate + * The object for which update shall be registered. + */ + public void update(String key, Object objectToUpdate) { + + if (ObjectFilter.logger.isDebugEnabled()) + ObjectFilter.logger.debug(MessageFormat.format("update object {0} with key {1}", objectToUpdate, key)); //$NON-NLS-1$ + + // BEWARE: you fix a bug here, be sure to update BOTH tables on the logic. + ObjectCache cached = this.cache.get(objectToUpdate); + if (cached == null) { + + // The object got an ID during this run, but was not added to this cache. + // Hence, we add it now, with the current operation. + ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectToUpdate, Operation.MODIFY); + this.cache.put(objectToUpdate, cacheObj); + + } else { + + String existingKey = cached.getKey(); + if (!existingKey.equals(key)) { + String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$ + throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id), + Operation.MODIFY.toString(), existingKey, key, objectToUpdate.toString())); + } + + // The object is in cache: update the version as required. + Operation op = cached.getOperation(); + switch (op) { + case ADD: + case MODIFY: + // replace key if necessary + replaceKey(cached.getObject(), objectToUpdate); + + // update operation's object + cached.setObject(objectToUpdate); + break; + case REMOVE: + throw new IllegalStateException("Stale State exception: Invalid += after -"); //$NON-NLS-1$ + default: + throw new IllegalStateException("Stale State exception: Unhandled state " + op); //$NON-NLS-1$ + } // switch + }// else of object not in cache + + // register the key + this.keySet.add(key); + } + + /** + * Register, under the given key, the removal of the given object. *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Action \ State in CacheN/AAdd(01)Update(O1)Remove(O1)
Remove (O2)Remove(O2)N/ARemove(O2)Err!
+ * + * @param key + * the key to register the object with + * @param objectToRemove + * The object for which removal shall be registered. + */ + public void remove(String key, Object objectToRemove) { + + if (ObjectFilter.logger.isDebugEnabled()) + ObjectFilter.logger.debug(MessageFormat.format("remove object {0} with key {1}", objectToRemove, key)); //$NON-NLS-1$ + + // BEWARE: you fix a bug here, be sure to update BOTH tables on the logic. + ObjectCache cached = this.cache.get(objectToRemove); + if (cached == null) { + // The object got an ID during this run, but was not added to this cache. + // Hence, we add it now, with the current operation. + ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectToRemove, Operation.REMOVE); + this.cache.put(objectToRemove, cacheObj); + } else { + + String existingKey = cached.getKey(); + if (!existingKey.equals(key)) { + String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$ + throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id), + Operation.REMOVE.toString(), existingKey, key, objectToRemove.toString())); + } + + // The object is in cache: update the version as required. + Operation op = cached.getOperation(); + switch (op) { + case ADD: + // this is a case where we're removing the object from the cache, since we are + // removing it now and it was added previously. + this.cache.remove(objectToRemove); + break; + case MODIFY: + // replace key if necessary + replaceKey(cached.getObject(), objectToRemove); + + // update operation's object + cached.setObject(objectToRemove); + cached.setOperation(Operation.REMOVE); + break; + case REMOVE: + throw new IllegalStateException("Stale State exception: Invalid - after -"); //$NON-NLS-1$ + default: + throw new IllegalStateException("Stale State exception: Unhandled state " + op); //$NON-NLS-1$ + } // switch + } + + // register the key + this.keySet.add(key); + } + + /** + * Register, under the given key, the addition of the given list of objects. + * + * @param key + * the key to register the objects with + * @param addedObjects + * The objects for which addition shall be registered. + */ + public void addAll(String key, Collection addedObjects) { + for (Object addObj : addedObjects) { + add(key, addObj); + } + } + + /** + * Register, under the given key, the update of the given list of objects. + * + * @param key + * the key to register the objects with + * @param updatedObjects + * The objects for which update shall be registered. + */ + public void updateAll(String key, Collection updatedObjects) { + for (Object update : updatedObjects) { + update(key, update); + } + } + + /** + * Register, under the given key, the removal of the given list of objects. + * + * @param key + * the key to register the objects with + * @param removedObjects + * The objects for which removal shall be registered. + */ + public void removeAll(String key, Collection removedObjects) { + for (Object removed : removedObjects) { + remove(key, removed); + } + } + + /** + * Register the addition of the given object. Since no key is provided, the class name is used as a key. + * + * @param object + * The object that shall be registered for addition + */ + public void add(Object object) { + add(object.getClass().getName(), object); + } + + /** + * Register the update of the given object. Since no key is provided, the class name is used as a key. + * + * @param object + * The object that shall be registered for updating + */ + public void update(Object object) { + update(object.getClass().getName(), object); + } + + /** + * Register the removal of the given object. Since no key is provided, the class name is used as a key. + * + * @param object + * The object that shall be registered for removal + */ + public void remove(Object object) { + remove(object.getClass().getName(), object); + } + + /** + * Register the addition of all objects in the list. Since no key is provided, the class name of each object is used + * as a key. + * + * @param objects + * The objects that shall be registered for addition + */ + public void addAll(List objects) { + for (Object addedObj : objects) { + add(addedObj.getClass().getName(), addedObj); + } + } + + /** + * Register the updating of all objects in the list. Since no key is provided, the class name of each object is used + * as a key. + * + * @param updateObjects + * The objects that shall be registered for updating + */ + public void updateAll(List updateObjects) { + for (Object update : updateObjects) { + update(update.getClass().getName(), update); + } + } + + /** + * Register the removal of all objects in the list. Since no key is provided, the class name of each object is used + * as a key. + * + * @param removedObjects + * The objects that shall be registered for removal + */ + public void removeAll(List removedObjects) { + for (Object removed : removedObjects) { + remove(removed.getClass().getName(), removed); + } + } + + /** + * Get all objects that were registered under the given key and that have as a resulting final action an addition. + * + * @param key + * The registration key of the objects to match + * + * @return The list of all objects registered under the given key and that need to be added. + */ + public List getAdded(String key) { + List addedObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getOperation() == Operation.ADD && (objectCache.getKey().equals(key))) { + addedObjects.add(objectCache.getObject()); + } + } + return addedObjects; + } + + /** + * Get all objects that were registered under the given key and that have as a resulting final action an addition. + * + * @param clazz + * The class type of the object to be retrieved, that acts as an additional filter criterion. + * @param key + * The registration key of the objects to match + * + * @return The list of all objects registered under the given key and that need to be added. + */ + public List getAdded(Class clazz, String key) { + List addedObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getOperation() == Operation.ADD && (objectCache.getKey().equals(key))) { + if (objectCache.getObject().getClass() == clazz) { + @SuppressWarnings("unchecked") + V object = (V) objectCache.getObject(); + addedObjects.add(object); + } + } + } + return addedObjects; + } + + /** + * Get all objects that were registered under the given key and that have as a resulting final action an update. + * + * @param key + * registration key of the objects to match + * + * @return The list of all objects registered under the given key and that need to be updated. + */ + public List getUpdated(String key) { + List updatedObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getOperation() == Operation.MODIFY && (objectCache.getKey().equals(key))) { + updatedObjects.add(objectCache.getObject()); + } + } + return updatedObjects; + } + + /** + * Get all objects that were registered under the given key and that have as a resulting final action an update. + * + * @param clazz + * The class type of the object to be retrieved, that acts as an additional filter criterion. + * @param key + * registration key of the objects to match + * + * @return The list of all objects registered under the given key and that need to be updated. + */ + public List getUpdated(Class clazz, String key) { + List updatedObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getOperation() == Operation.MODIFY && (objectCache.getKey().equals(key))) { + if (objectCache.getObject().getClass() == clazz) { + @SuppressWarnings("unchecked") + V object = (V) objectCache.getObject(); + updatedObjects.add(object); + } + } + } + return updatedObjects; + } + + /** + * Get all objects that were registered under the given key that have as a resulting final action their removal. + * + * @param key + * The registration key of the objects to match + * + * @return The list of object registered under the given key that have, as a final action, removal. + */ + public List getRemoved(String key) { + List removedObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getOperation() == Operation.REMOVE && (objectCache.getKey().equals(key))) { + removedObjects.add(objectCache.getObject()); + } + } + return removedObjects; + } + + /** + * Get all objects that were registered under the given key that have as a resulting final action their removal. + * + * @param clazz + * The class type of the object to be retrieved, that acts as an additional filter criterion. + * @param key + * The registration key of the objects to match + * + * @return The list of object registered under the given key that have, as a final action, removal. + */ + public List getRemoved(Class clazz, String key) { + List removedObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getOperation() == Operation.REMOVE && (objectCache.getKey().equals(key))) { + if (objectCache.getObject().getClass() == clazz) { + @SuppressWarnings("unchecked") + V object = (V) objectCache.getObject(); + removedObjects.add(object); + } + } + } + return removedObjects; + } + + /** + * Get all objects that were registered under the given key + * + * @param clazz + * The class type of the object to be retrieved, that acts as an additional filter criterion. + * @param key + * The registration key of the objects to match + * + * @return The list of object registered under the given key that have, as a final action, removal. + */ + public List getAll(Class clazz, String key) { + List objects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getKey().equals(key)) { + if (objectCache.getObject().getClass() == clazz) { + @SuppressWarnings("unchecked") + V object = (V) objectCache.getObject(); + objects.add(object); + } + } + } + return objects; + } + + /** + * Get all objects that of the given class + * + * @param clazz + * The class type of the object to be retrieved, that acts as an additional filter criterion. + * + * @return The list of all objects that of the given class + */ + public List getAll(Class clazz) { + List objects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getObject().getClass() == clazz) { + @SuppressWarnings("unchecked") + V object = (V) objectCache.getObject(); + objects.add(object); + } + } + return objects; + } + + /** + * Get all the objects that were processed in this transaction, that were registered under the given key. No action + * is associated to the object. + * + * @param key + * The registration key for which the objects shall be retrieved + * + * @return The list of objects matching the given key. + */ + public List getAll(String key) { + List allObjects = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getKey().equals(key)) { + allObjects.add(objectCache.getObject()); + } + } + return allObjects; + } + + /** + * Get all the objects that were processed in this transaction, that were registered under the given key. No action + * is associated to the object. + * + * @param key + * The registration key for which the objects shall be retrieved + * + * @return The list of objects matching the given key. + */ + public List getCache(String key) { + List allCache = new LinkedList<>(); + Collection allObjs = this.cache.values(); + for (ObjectCache objectCache : allObjs) { + if (objectCache.getKey().equals(key)) { + allCache.add(objectCache); + } + } + return allCache; + } + + /** + * Return the set of keys that are currently present in the object filter. + * + * @return The set containing the keys of that have been added to the filter. + */ + public Set keySet() { + return this.keySet; + } + + /** + * Clears the cache + */ + public void clearCache() { + this.cache.clear(); + this.keySet.clear(); + } + + /** + * @return the set of keys used to register objects + */ + public int sizeKeySet() { + return this.keySet.size(); + } + + /** + * @return the number of objects registered in this filter + */ + public int sizeCache() { + return this.cache.size(); + } + + /** + * @return get a unique transaction ID + */ + public synchronized long dispenseID() { + ObjectFilter.id++; + if (ObjectFilter.id == Long.MAX_VALUE) { + ObjectFilter.logger.error("Rolling IDs of objectFilter back to 1. Hope this is fine."); //$NON-NLS-1$ + ObjectFilter.id = 1; + } + return ObjectFilter.id; + } +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/Operation.java b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/Operation.java new file mode 100644 index 000000000..21ae1c2b8 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/Operation.java @@ -0,0 +1,36 @@ +/* + * Copyright 2013 Michael Gatto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.objectfilter; + +/** + * A discrete set of operations associated to some object / state + * + * @author Michael Gatto + */ +public enum Operation { + /** + * ADD The operation associated to something is addition. + */ + ADD, + /** + * MODIFY The operation associated to something is a modification. + */ + MODIFY, + /** + * REMOVE The operation associated to something is removal + */ + REMOVE; +} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/xml/XmlKeyValue.java b/li.strolch.utils/src/main/java/li/strolch/utils/xml/XmlKeyValue.java new file mode 100644 index 000000000..7856fc1a7 --- /dev/null +++ b/li.strolch.utils/src/main/java/li/strolch/utils/xml/XmlKeyValue.java @@ -0,0 +1,73 @@ +package li.strolch.utils.xml; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.xml.bind.annotation.XmlAttribute; + +public class XmlKeyValue { + + @XmlAttribute(name = "key") + private String key; + @XmlAttribute(name = "value") + private String value; + + public XmlKeyValue(String key, String value) { + this.key = key; + this.value = value; + } + + public XmlKeyValue() { + // no-arg constructor for JAXB + } + + /** + * @return the key + */ + public String getKey() { + return this.key; + } + + /** + * @param key + * the key to set + */ + public void setKey(String key) { + this.key = key; + } + + /** + * @return the value + */ + public String getValue() { + return this.value; + } + + /** + * @param value + * the value to set + */ + public void setValue(String value) { + this.value = value; + } + + public static List valueOf(Map map) { + List keyValues = new ArrayList<>(map.size()); + for (Entry entry : map.entrySet()) { + keyValues.add(new XmlKeyValue(entry.getKey(), entry.getValue())); + } + return keyValues; + } + + public static Map toMap(List values) { + Map propertyMap = new HashMap<>(values.size()); + for (XmlKeyValue xmlKeyValue : values) { + propertyMap.put(xmlKeyValue.getKey(), xmlKeyValue.getValue()); + } + + return propertyMap; + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/log4j.xml b/li.strolch.utils/src/main/java/log4j.xml new file mode 100644 index 000000000..7a0499275 --- /dev/null +++ b/li.strolch.utils/src/main/java/log4j.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/AbstractEndpointTest.java b/li.strolch.utils/src/test/java/li/strolch/communication/AbstractEndpointTest.java new file mode 100644 index 000000000..e53f93825 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/AbstractEndpointTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.CommandKey; + +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +public class AbstractEndpointTest { + + static final Logger logger = LoggerFactory.getLogger(FileEndpointTest.class); + + public static TestIoMessage createTestMessage(String key1, String key2, String connectionId) { + return createTestMessage(CommandKey.key(key1, key2), connectionId); + } + + @SuppressWarnings("nls") + public static TestIoMessage createTestMessage(CommandKey key, String connectionId) { + TestIoMessage msg = new TestIoMessage(UUID.randomUUID().toString(), key, connectionId); + List lines = new ArrayList<>(); + lines.add("bla"); + lines.add("foo"); + lines.add("bar"); + lines.add("bla"); + msg.setContents(lines); + return msg; + } + + protected void waitForMessage(TestConnectionObserver observer) throws InterruptedException { + long start = System.currentTimeMillis(); + while (observer.getMessage() == null) { + if (System.currentTimeMillis() - start > 2000) + fail("Connection didn't send message in 2s!"); //$NON-NLS-1$ + Thread.sleep(50); + } + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/ConsoleEndpointTest.java b/li.strolch.utils/src/test/java/li/strolch/communication/ConsoleEndpointTest.java new file mode 100644 index 000000000..852d9a5ec --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/ConsoleEndpointTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionMode; +import li.strolch.communication.IoMessage; +import li.strolch.communication.console.ConsoleEndpoint; +import li.strolch.communication.console.ConsoleMessageVisitor; + +/** + * @author Robert von Burg + */ +public class ConsoleEndpointTest extends AbstractEndpointTest { + + private static final String CONNECTION_ID = "Console"; //$NON-NLS-1$ + private CommunicationConnection connection; + + @Before + public void before() { + + Map parameters = new HashMap<>(); + CommunicationEndpoint endpoint = new ConsoleEndpoint(); + ConsoleMessageVisitor messageVisitor = new ConsoleMessageVisitorExtension(); + this.connection = new CommunicationConnection(CONNECTION_ID, ConnectionMode.ON, parameters, endpoint, + messageVisitor); + this.connection.configure(); + } + + @Test + public void testConsoleEndpoint() throws InterruptedException { + + this.connection.start(); + + CommandKey key = CommandKey.key(CONNECTION_ID, "logger"); //$NON-NLS-1$ + TestIoMessage msg = createTestMessage(key, CONNECTION_ID); + + TestConnectionObserver observer = new TestConnectionObserver(); + this.connection.addConnectionObserver(key, observer); + this.connection.send(msg); + waitForMessage(observer); + + assertEquals(msg.getKey(), observer.getMessage().getKey()); + + } + + private final class ConsoleMessageVisitorExtension extends ConsoleMessageVisitor { + public ConsoleMessageVisitorExtension() { + // no-op + } + + @Override + public void visit(Logger logger, IoMessage message) throws Exception { + TestIoMessage msg = (TestIoMessage) message; + for (String line : msg.getContents()) { + logger.info(line); + } + } + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/FileEndpointTest.java b/li.strolch.utils/src/test/java/li/strolch/communication/FileEndpointTest.java new file mode 100644 index 000000000..e4da66b04 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/FileEndpointTest.java @@ -0,0 +1,144 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionMode; +import li.strolch.communication.IoMessage; +import li.strolch.communication.StreamMessageVisitor; +import li.strolch.communication.file.FileEndpoint; +import li.strolch.communication.file.FileEndpointMode; +import li.strolch.utils.helper.FileHelper; + +/** + * @author Robert von Burg + */ +public class FileEndpointTest extends AbstractEndpointTest { + + public static final String INBOUND_FILENAME = "target/test_in.txt"; //$NON-NLS-1$ + public static final String OUTBOUND_FILENAME = "target/test_out.txt"; //$NON-NLS-1$ + public static final String CONNECTION_ID = "FileTestEndpoint"; //$NON-NLS-1$ + + private CommunicationConnection connection; + + @Before + public void before() { + + new File(OUTBOUND_FILENAME).delete(); + new File(INBOUND_FILENAME).delete(); + + Map parameters = new HashMap<>(); + parameters.put(FileEndpoint.ENDPOINT_MODE, FileEndpointMode.READ_WRITE.name()); + parameters.put(FileEndpoint.INBOUND_FILENAME, INBOUND_FILENAME); + parameters.put(FileEndpoint.OUTBOUND_FILENAME, OUTBOUND_FILENAME); + + ConnectionMode mode = ConnectionMode.ON; + CommunicationEndpoint endpoint = new FileEndpoint(); + StreamMessageVisitor messageVisitor = new StreamMessageVisitorExtension(); + + this.connection = new CommunicationConnection(CONNECTION_ID, mode, parameters, endpoint, messageVisitor); + this.connection.configure(); + } + + @After + public void after() { + if (this.connection != null) + this.connection.stop(); + } + + @Test + public void testFileEndpoint() throws InterruptedException { + + String inboundFilename = new File(INBOUND_FILENAME).getName(); + String outboundFilename = new File(OUTBOUND_FILENAME).getName(); + + // send a message + this.connection.start(); + TestConnectionObserver outboundObserver = new TestConnectionObserver(); + TestIoMessage message = createTestMessage(outboundFilename, FileEndpointMode.WRITE.name(), CONNECTION_ID); + this.connection.addConnectionObserver(message.getKey(), outboundObserver); + this.connection.send(message); + + // wait till the message has been sent + waitForMessage(outboundObserver); + this.connection.stop(); + assertEquals(message.getKey(), outboundObserver.getMessage().getKey()); + + // now test reading a file + this.connection.start(); + CommandKey inboundKey = CommandKey.key(inboundFilename, FileEndpointMode.READ.name()); + TestConnectionObserver inboundObserver = new TestConnectionObserver(); + this.connection.addConnectionObserver(inboundKey, inboundObserver); + FileHelper.writeStringToFile("Hello\nWorld!", new File(INBOUND_FILENAME)); //$NON-NLS-1$ + + // wait for thread to pick up the file + waitForMessage(inboundObserver); + assertEquals(inboundKey, inboundObserver.getMessage().getKey()); + } + + public static final class StreamMessageVisitorExtension extends StreamMessageVisitor { + private String inboundFilename; + + @Override + public void configure(CommunicationConnection connection) { + super.configure(connection); + Map parameters = connection.getParameters(); + String filePath = parameters.get(FileEndpoint.INBOUND_FILENAME); + this.inboundFilename = new File(filePath).getName(); + } + + @Override + public IoMessage visit(InputStream inputStream) throws Exception { + + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + List lines = new ArrayList<>(); + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + return new TestIoMessage(UUID.randomUUID().toString(), CommandKey.key(this.inboundFilename, + FileEndpointMode.READ.name()), CONNECTION_ID, lines); + } + + @Override + public void visit(OutputStream outputStream, IoMessage message) throws Exception { + TestIoMessage msg = (TestIoMessage) message; + for (String line : msg.getContents()) { + outputStream.write(line.getBytes()); + outputStream.write('\n'); + } + } + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/SimpleMessageArchiveTest.java b/li.strolch.utils/src/test/java/li/strolch/communication/SimpleMessageArchiveTest.java new file mode 100644 index 000000000..ea38127f4 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/SimpleMessageArchiveTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import static org.junit.Assert.assertEquals; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.junit.Test; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.IoMessage; +import li.strolch.communication.IoMessageArchive; +import li.strolch.communication.SimpleMessageArchive; + +/** + * @author Robert von Burg + */ +public class SimpleMessageArchiveTest extends AbstractEndpointTest { + + @Test + public void testArchive() throws InterruptedException { + + IoMessageArchive archive = new SimpleMessageArchive(20, 5); + + CommandKey key = CommandKey.key("key1", "key2"); //$NON-NLS-1$//$NON-NLS-2$ + String connectionId = "connection1"; //$NON-NLS-1$ + + int i = 0; + for (; i < 20; i++) { + TestIoMessage msg = new TestIoMessage(UUID.randomUUID().toString(), key, connectionId); + // update the time by plus 1, otherwise the tree set does not add it + msg.setUpdated(new Date(i + 1)); + archive.archive(msg); + } + + assertEquals(20, archive.size()); + + // add one more + TestIoMessage msg = new TestIoMessage(UUID.randomUUID().toString(), key, connectionId); + msg.setUpdated(new Date(i + 1)); + archive.archive(msg); + + // validate the trimming works + assertEquals(15, archive.size()); + + // Now make sure our last element is still in the list + List all = archive.getAll(); + Collections.sort(all, new Comparator() { + @Override + public int compare(IoMessage o1, IoMessage o2) { + return o1.getUpdated().compareTo(o2.getUpdated()); + } + }); + IoMessage message = all.get(all.size() - 1); + assertEquals(msg.getId(), message.getId()); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/SocketEndpointTest.java b/li.strolch.utils/src/test/java/li/strolch/communication/SocketEndpointTest.java new file mode 100644 index 000000000..bd2d5007c --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/SocketEndpointTest.java @@ -0,0 +1,159 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStreamReader; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.CommunicationConnection; +import li.strolch.communication.CommunicationEndpoint; +import li.strolch.communication.ConnectionMode; +import li.strolch.communication.IoMessage; +import li.strolch.communication.tcpip.ClientSocketEndpoint; +import li.strolch.communication.tcpip.ServerSocketEndpoint; +import li.strolch.communication.tcpip.SocketEndpointConstants; +import li.strolch.communication.tcpip.SocketMessageVisitor; + +/** + * @author Robert von Burg + */ +public class SocketEndpointTest extends AbstractEndpointTest { + + private static final String PORT = "45678"; //$NON-NLS-1$ + private static final String HOST = "localhost"; //$NON-NLS-1$ + private static final String CLIENT_CONNECTION_ID = "ClientSocket"; //$NON-NLS-1$ + private static final String SERVER_CONNECTION_ID = "ServerSocket"; //$NON-NLS-1$ + private CommunicationConnection clientConnection; + private CommunicationConnection serverConnection; + + @Before + public void before() { + + { + Map parameters = new HashMap<>(); + parameters.put(SocketEndpointConstants.PARAMETER_REMOTE_INPUT_ADDRESS, HOST); + parameters.put(SocketEndpointConstants.PARAMETER_REMOTE_INPUT_PORT, PORT); + + // we close after send, so that the server can read whole lines, as that is what we are sending + parameters.put(SocketEndpointConstants.PARAMETER_CLOSE_AFTER_SEND, Boolean.TRUE.toString()); + + CommunicationEndpoint endpoint = new ClientSocketEndpoint(); + SocketMessageVisitor messageVisitor = new SocketMessageVisitorExtension(CLIENT_CONNECTION_ID); + this.clientConnection = new CommunicationConnection(CLIENT_CONNECTION_ID, ConnectionMode.ON, parameters, + endpoint, messageVisitor); + this.clientConnection.configure(); + } + + { + Map parameters = new HashMap<>(); + parameters.put(SocketEndpointConstants.PARAMETER_LOCAL_INPUT_ADDRESS, HOST); + parameters.put(SocketEndpointConstants.PARAMETER_LOCAL_INPUT_PORT, PORT); + + CommunicationEndpoint endpoint = new ServerSocketEndpoint(); + SocketMessageVisitor messageVisitor = new SocketMessageVisitorExtension(SERVER_CONNECTION_ID); + this.serverConnection = new CommunicationConnection(SERVER_CONNECTION_ID, ConnectionMode.ON, parameters, + endpoint, messageVisitor); + this.serverConnection.configure(); + } + } + + @After + public void after() { + if (this.clientConnection != null) + this.clientConnection.stop(); + if (this.serverConnection != null) + this.serverConnection.stop(); + } + + @Test + public void testSocketEndpoints() throws Exception { + + this.serverConnection.start(); + Thread.sleep(100); + this.clientConnection.start(); + + TestConnectionObserver serverObserver = new TestConnectionObserver(); + CommandKey inboundKey = CommandKey.key(SERVER_CONNECTION_ID, "lines"); //$NON-NLS-1$ + this.serverConnection.addConnectionObserver(inboundKey, serverObserver); + + TestConnectionObserver clientObserver = new TestConnectionObserver(); + CommandKey outboundKey = CommandKey.key(CLIENT_CONNECTION_ID, "lines"); //$NON-NLS-1$ + this.clientConnection.addConnectionObserver(outboundKey, clientObserver); + + TestIoMessage outboundMsg = createTestMessage(outboundKey, CLIENT_CONNECTION_ID); + this.clientConnection.send(outboundMsg); + waitForMessage(clientObserver); + assertEquals(outboundMsg.getKey(), clientObserver.getMessage().getKey()); + + waitForMessage(serverObserver); + assertEquals(inboundKey, serverObserver.getMessage().getKey()); + assertEquals(outboundMsg.getContents(), ((TestIoMessage) serverObserver.getMessage()).getContents()); + } + + private final class SocketMessageVisitorExtension extends SocketMessageVisitor { + + public SocketMessageVisitorExtension(String connectionId) { + super(connectionId); + } + + @Override + public void visit(DataInputStream inputStream, DataOutputStream outputStream, IoMessage message) + throws Exception { + TestIoMessage msg = (TestIoMessage) message; + logger.info(MessageFormat + .format("Writing {0} lines for message {1}", msg.getContents().size(), msg.getId())); //$NON-NLS-1$ + for (String line : msg.getContents()) { + outputStream.writeBytes(line); + outputStream.write('\n'); + } + outputStream.flush(); + } + + @Override + public IoMessage visit(DataInputStream inputStream, DataOutputStream outputStream) throws Exception { + + List lines = new ArrayList<>(); + + // since we are reading whole lines, we must close the stream when we read null i.e. EOF + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + logger.info("Reading from stream..."); //$NON-NLS-1$ + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } + logger.info(MessageFormat.format("Read {0} lines from stream.", lines.size())); //$NON-NLS-1$ + + return new TestIoMessage(UUID.randomUUID().toString(), + CommandKey.key(SERVER_CONNECTION_ID, "lines"), SERVER_CONNECTION_ID, lines); //$NON-NLS-1$ + } + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/TestConnectionObserver.java b/li.strolch.utils/src/test/java/li/strolch/communication/TestConnectionObserver.java new file mode 100644 index 000000000..818b1b3e3 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/TestConnectionObserver.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.text.MessageFormat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.ConnectionObserver; +import li.strolch.communication.IoMessage; + +/** + * @author Robert von Burg + */ +public class TestConnectionObserver implements ConnectionObserver { + + private static final Logger logger = LoggerFactory.getLogger(FileEndpointTest.class); + + private IoMessage message; + + public IoMessage getMessage() { + return this.message; + } + + @Override + public void notify(CommandKey key, IoMessage message) { + this.message = message; + logger.info(MessageFormat.format("Received message with key {0} and message {1}", key, message)); //$NON-NLS-1$ + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/test/java/li/strolch/communication/TestIoMessage.java b/li.strolch.utils/src/test/java/li/strolch/communication/TestIoMessage.java new file mode 100644 index 000000000..72b583bd0 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/communication/TestIoMessage.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.communication; + +import java.util.List; + +import li.strolch.communication.CommandKey; +import li.strolch.communication.IoMessage; + +/** + * @author Robert von Burg + */ +public class TestIoMessage extends IoMessage { + + private List contents; + + public TestIoMessage(String id, CommandKey key, String connectionId) { + super(id, key, connectionId); + } + + public TestIoMessage(String id, CommandKey key, String connectionId, List contents) { + super(id, key, connectionId); + this.contents = contents; + } + + public List getContents() { + return this.contents; + } + + public void setContents(List contents) { + this.contents = contents; + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/StringMatchModeTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/StringMatchModeTest.java new file mode 100644 index 000000000..fb318d741 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/StringMatchModeTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import li.strolch.utils.StringMatchMode; + +/** + * @author Robert von Burg + * + */ +public class StringMatchModeTest { + + /** + * Test method for {@link li.strolch.utils.StringMatchMode#isCaseSensitve()}. + */ + @Test + public void testIsCaseSensitve() { + assertFalse(StringMatchMode.EQUALS_CASE_INSENSITIVE.isCaseSensitve()); + assertTrue(StringMatchMode.EQUALS_CASE_SENSITIVE.isCaseSensitve()); + assertFalse(StringMatchMode.CONTAINS_CASE_INSENSITIVE.isCaseSensitve()); + assertTrue(StringMatchMode.CONTAINS_CASE_SENSITIVE.isCaseSensitve()); + } + + /** + * Test method for {@link li.strolch.utils.StringMatchMode#isEquals()}. + */ + @Test + public void testIsEquals() { + assertTrue(StringMatchMode.EQUALS_CASE_INSENSITIVE.isEquals()); + assertTrue(StringMatchMode.EQUALS_CASE_SENSITIVE.isEquals()); + assertFalse(StringMatchMode.CONTAINS_CASE_INSENSITIVE.isEquals()); + assertFalse(StringMatchMode.CONTAINS_CASE_SENSITIVE.isEquals()); + } + + /** + * Test method for {@link li.strolch.utils.StringMatchMode#matches(java.lang.String, java.lang.String)}. + */ + @SuppressWarnings("nls") + @Test + public void testMatches() { + assertTrue(StringMatchMode.CONTAINS_CASE_INSENSITIVE.matches("hello", "el")); + assertTrue(StringMatchMode.CONTAINS_CASE_SENSITIVE.matches("hello", "el")); + assertFalse(StringMatchMode.CONTAINS_CASE_SENSITIVE.matches("hello", "ael")); + assertFalse(StringMatchMode.CONTAINS_CASE_SENSITIVE.matches("hello", "EL")); + assertFalse(StringMatchMode.CONTAINS_CASE_SENSITIVE.matches("hello", "aEL")); + assertTrue(StringMatchMode.CONTAINS_CASE_INSENSITIVE.matches("hello", "EL")); + + assertTrue(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "ab")); + assertFalse(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "abc")); + assertTrue(StringMatchMode.EQUALS_CASE_INSENSITIVE.matches("ab", "ab")); + assertTrue(StringMatchMode.EQUALS_CASE_INSENSITIVE.matches("ab", "AB")); + assertTrue(StringMatchMode.EQUALS_CASE_INSENSITIVE.matches("ab", "aB")); + + assertFalse(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "aB")); + assertFalse(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "aB")); + assertFalse(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "AB")); + assertFalse(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "aba")); + assertTrue(StringMatchMode.EQUALS_CASE_SENSITIVE.matches("ab", "ab")); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/VersionTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/VersionTest.java new file mode 100644 index 000000000..e675f5ff0 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/VersionTest.java @@ -0,0 +1,108 @@ +package li.strolch.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import li.strolch.utils.Version; +import li.strolch.utils.helper.StringHelper; + +/** + * Tests the {@link Version} class + */ +public class VersionTest { + + @Test + public void shouldParseMajoMinoMicro() { + Version version = Version.valueOf("1.0.2"); + assertEquals(1, version.getMajor()); + assertEquals(0, version.getMinor()); + assertEquals(2, version.getMicro()); + assertEquals(StringHelper.EMPTY, version.getQualifier()); + assertEquals(StringHelper.EMPTY, version.getQualifier()); + + assertEquals("1.0.2", version.toString()); + } + + @Test + public void shouldParseVersion() { + { + Version version = Version.valueOf("7.5.6.1"); + assertEquals(7, version.getMajor()); + assertEquals(5, version.getMinor()); + assertEquals(6, version.getMicro()); + assertEquals("1", version.getQualifier()); + assertTrue(version.isOsgiStyle()); + } + { + Version version = Version.valueOf("7.5.6-1"); + assertEquals(7, version.getMajor()); + assertEquals(5, version.getMinor()); + assertEquals(6, version.getMicro()); + assertEquals("1", version.getQualifier()); + assertFalse(version.isOsgiStyle()); + } + } + + @Test + public void shouldCompareVersions() { + assertEquals(0, Version.valueOf("7.5.6-1").compareTo(Version.valueOf("7.5.6-1"))); + assertTrue(Version.valueOf("7.5.6-1").compareTo(Version.valueOf("7.5.6-2")) < 0); + assertTrue(Version.valueOf("7.5.6-1").compareTo(Version.valueOf("7.6.0")) < 0); + assertTrue(Version.valueOf("7.5.6-1").compareTo(Version.valueOf("7.6.1")) < 0); + assertTrue(Version.valueOf("7.5.6-alpha").compareTo(Version.valueOf("7.6.1-beta")) < 0); + assertTrue(Version.valueOf("7.7.0-0").compareTo(Version.valueOf("7.6.99-9")) > 0); + assertTrue(Version.valueOf("0.0.1.a").compareTo(Version.valueOf("0.0.1.b")) < 0); + assertTrue(Version.valueOf("0.0.1.b").compareTo(Version.valueOf("0.0.1.a")) > 0); + assertTrue(Version.valueOf("0.0.1.a").compareTo(Version.valueOf("0.0.1.c")) < 0); + assertTrue(Version.valueOf("0.0.1.a").compareTo(Version.valueOf("0.0.1.aa")) < 0); + } + + @Test + public void shouldConvertToMajorMinorString() { + assertEquals("7.6", Version.valueOf("7.6.1-0").toMajorAndMinorString()); + } + + @Test + public void shouldKnowAboutBeingFullyQualified() { + assertFalse(Version.valueOf("7").isFullyQualified()); + assertFalse(Version.valueOf("7.6").isFullyQualified()); + assertFalse(Version.valueOf("7.6.1").isFullyQualified()); + assertTrue(Version.valueOf("7.6.1-0").isFullyQualified()); + } + + @Test + public void shouldDealWithEclipseStyleSnapshotQualifier() { + assertEquals(Version.valueOf("7.6.1-SNAPSHOT").toOsgiStyleString(), "7.6.1.qualifier"); + assertEquals(Version.valueOf("7.6.1-SNAPSHOT").toMavenStyleString(), "7.6.1-SNAPSHOT"); + assertEquals(Version.valueOf("7.6.1.qualifier").toOsgiStyleString(), "7.6.1.qualifier"); + assertEquals(Version.valueOf("7.6.1.qualifier").toMavenStyleString(), "7.6.1-SNAPSHOT"); + } + + @Test + public void shouldIncreaseVersion() { + + Version increased = Version.emptyVersion.add(0, 0, 0); + assertEquals("0.0.0", increased.toString()); + + increased = increased.add(0, 0, 1); + assertEquals("0.0.1", increased.toString()); + + increased = increased.add(0, 1, 0); + assertEquals("0.1.1", increased.toString()); + + increased = increased.add(1, 0, 0); + assertEquals("1.1.1", increased.toString()); + + increased = increased.add(-1, 0, 0); + assertEquals("0.1.1", increased.toString()); + + increased = increased.add(0, -1, 0); + assertEquals("0.0.1", increased.toString()); + + increased = increased.add(0, 0, -1); + assertEquals("0.0.0", increased.toString()); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/collections/DateRangeTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/collections/DateRangeTest.java new file mode 100644 index 000000000..9bc4ef5c1 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/collections/DateRangeTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Date; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import li.strolch.utils.collections.DateRange; +import li.strolch.utils.dbc.DBC.DbcException; + +public class DateRangeTest { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Test + public void testFrom() { + Date now = new Date(); + DateRange dateRange = new DateRange(); + dateRange.from(now, true); + assertEquals(now, dateRange.getFromDate()); + assertNull(dateRange.getToDate()); + assertFalse(dateRange.isUnbounded()); + assertFalse(dateRange.isBounded()); + } + + /** + * Test method for {@link li.strolch.utils.collections.DateRange#to(java.util.Date, boolean)}. + */ + @Test + public void testTo() { + Date now = new Date(); + DateRange dateRange = new DateRange(); + dateRange.to(now, true); + assertEquals(now, dateRange.getToDate()); + assertNull(dateRange.getFromDate()); + assertFalse(dateRange.isUnbounded()); + assertFalse(dateRange.isBounded()); + } + + /** + * Test method for {@link li.strolch.utils.collections.DateRange#to(java.util.Date,boolean)}. + */ + @Test + public void testFromTo() { + Date from = new Date(); + Date to = new Date(); + DateRange dateRange = new DateRange(); + dateRange.from(from, true).to(to, true); + assertEquals(from, dateRange.getFromDate()); + assertEquals(to, dateRange.getToDate()); + assertFalse(dateRange.isUnbounded()); + assertTrue(dateRange.isBounded()); + } + + @Test + public void shouldNotOverlap() { + this.exception.expect(DbcException.class); + Date from = new Date(10); + Date to = new Date(20); + DateRange dateRange = new DateRange(); + dateRange.from(to, true).to(from, true); + } + + /** + * Test method for {@link li.strolch.utils.collections.DateRange#isDate()}. + */ + @Test + public void testIsDate() { + + Date from = new Date(10); + Date to = new Date(20); + DateRange dateRange = new DateRange(); + dateRange.from(from, false).to(to, false); + assertFalse(dateRange.isDate()); + + dateRange = new DateRange(); + dateRange.from(from, false).to(from, false); + assertTrue(dateRange.isDate()); + } + + /** + * Test method for {@link li.strolch.utils.collections.DateRange#contains(java.util.Date)}. + */ + @Test + public void testContains() { + Date from = new Date(10); + Date to = new Date(20); + DateRange dateRange = new DateRange(); + dateRange.from(from, false).to(to, false); + + Date earlier = new Date(5); + Date later = new Date(25); + Date contained = new Date(15); + + assertFalse(dateRange.contains(earlier)); + assertFalse(dateRange.contains(later)); + assertTrue(dateRange.contains(contained)); + + assertFalse(dateRange.contains(from)); + assertFalse(dateRange.contains(to)); + + dateRange = new DateRange(); + dateRange.from(from, true).to(to, true); + assertTrue(dateRange.contains(from)); + assertTrue(dateRange.contains(to)); + + dateRange = new DateRange(); + dateRange.from(from, false).to(to, true); + assertFalse(dateRange.contains(from)); + assertTrue(dateRange.contains(to)); + + dateRange = new DateRange(); + dateRange.from(from, true).to(to, false); + assertTrue(dateRange.contains(from)); + assertFalse(dateRange.contains(to)); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/collections/DefaultedHashMapTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/collections/DefaultedHashMapTest.java new file mode 100644 index 000000000..01e8ff8ea --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/collections/DefaultedHashMapTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2015 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import li.strolch.utils.collections.DefaultedHashMap; + +/** + * @author Robert von Burg + */ +public class DefaultedHashMapTest { + + private Map map; + + @Before + public void setUp() { + this.map = new DefaultedHashMap<>("foobar"); + this.map.put("foo", "foofoo"); + } + + @Test + public void shouldReturnMappedValue() { + assertTrue(this.map.containsKey("foo")); + assertEquals("foofoo", this.map.get("foo")); + } + + @Test + public void shouldReturnDefaultValue() { + assertFalse(this.map.containsKey("bar")); + assertEquals("foobar", this.map.get("bar")); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java new file mode 100644 index 000000000..edf470704 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2015 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.collections; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import li.strolch.utils.collections.Paging; + +/** + * @author Robert von Burg + */ +public class PagingTest { + + @Test + public void shouldReturnAll() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, -1, -1).getPage(); + assertEquals(list, page); + } + + @Test + public void shouldReturnFirstPage1() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, 1, 1).getPage(); + assertEquals(Arrays.asList("a"), page); + } + + @Test + public void shouldReturnFirstPage2() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, 2, 1).getPage(); + assertEquals(Arrays.asList("a", "b"), page); + } + + @Test + public void shouldReturnSecondPage1() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, 1, 2).getPage(); + assertEquals(Arrays.asList("b"), page); + } + + @Test + public void shouldReturnSecondPage2() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, 2, 2).getPage(); + assertEquals(Arrays.asList("c", "d"), page); + } + + @Test + public void shouldReturnLastPage1() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, 1, 6).getPage(); + assertEquals(Arrays.asList("f"), page); + } + + @Test + public void shouldReturnLastPage2() { + List list = Arrays.asList("a", "b", "c", "d", "e", "f"); + List page = Paging.asPage(list, 2, 3).getPage(); + assertEquals(Arrays.asList("e", "f"), page); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/dbc/DBCTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/dbc/DBCTest.java new file mode 100644 index 000000000..6eaf1b192 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/dbc/DBCTest.java @@ -0,0 +1,495 @@ +/* + * Copyright 2014 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.dbc; + +import java.io.File; +import java.text.MessageFormat; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import li.strolch.utils.dbc.DBC; +import li.strolch.utils.dbc.DBC.DbcException; + +/** + * The class DBCTest contains tests for the class {@link DBC}. + * + * @generatedBy CodePro at 2/2/14 8:13 PM + * @author Robert von Burg + * @version $Revision: 1.0 $ + */ +@SuppressWarnings("nls") +public class DBCTest { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertEquals_1() throws Exception { + String msg = ""; + Object value1 = null; + Object value2 = null; + + DBC.PRE.assertEquals(msg, value1, value2); + + // add additional test code here + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertEquals_2() throws Exception { + this.exception.expect(DbcException.class); + Object value1 = new Object(); + Object value2 = new Object(); + String msg = MessageFormat.format("{0}: {1} != {2}", "", value1, value2); + this.exception.expectMessage(msg); + + DBC.PRE.assertEquals(msg, value1, value2); + + // add additional test code here + // An unexpected exception was thrown in user code while executing this test: + // li.strolch.utils.DBC.PRE.DBC$DbcException: Values are not equal: + // at li.strolch.utils.DBC.PRE.DBC.PRE.assertEquals(DBC.PRE.java:39) + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertEquals_3() throws Exception { + this.exception.expect(DbcException.class); + + Object value1 = null; + Object value2 = new Object(); + + String msg = MessageFormat.format("{0}: {1} != {2}", "", value1, value2); + this.exception.expectMessage(msg); + + DBC.PRE.assertEquals(msg, value1, value2); + + // add additional test code here + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertEquals_4() throws Exception { + this.exception.expect(DbcException.class); + + Object value1 = new Object(); + Object value2 = null; + + String msg = MessageFormat.format("{0}: {1} != {2}", "", value1, value2); + this.exception.expectMessage(msg); + + DBC.PRE.assertEquals(msg, value1, value2); + + // add additional test code here + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertEquals_5() throws Exception { + String msg = ""; + Object value1 = "bla"; + Object value2 = "bla"; + + DBC.PRE.assertEquals(msg, value1, value2); + + // add additional test code here + // An unexpected exception was thrown in user code while executing this test: + // li.strolch.utils.DBC.PRE.DBC$DbcException: Values are not equal: + // at li.strolch.utils.DBC.PRE.DBC.PRE.assertEquals(DBC.PRE.java:39) + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEquals_1() throws Exception { + this.exception.expect(DbcException.class); + + String msg = ""; + Object value1 = null; + Object value2 = null; + + String ex = "{0}: {1} == {2}"; + ex = MessageFormat.format(ex, msg, value1, value2); + this.exception.expectMessage(ex); + + DBC.PRE.assertNotEquals(msg, value1, value2); + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEquals_2() throws Exception { + String msg = ""; + Object value1 = new Object(); + Object value2 = new Object(); + + DBC.PRE.assertNotEquals(msg, value1, value2); + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEquals_3() throws Exception { + String msg = ""; + Object value1 = null; + Object value2 = new Object(); + + DBC.PRE.assertNotEquals(msg, value1, value2); + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEquals_4() throws Exception { + String msg = ""; + Object value1 = new Object(); + Object value2 = null; + + DBC.PRE.assertNotEquals(msg, value1, value2); + } + + /** + * Run the void assertEquals(String,Object,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEquals_5() throws Exception { + this.exception.expect(DbcException.class); + + String msg = ""; + Object value1 = "bla"; + Object value2 = "bla"; + + String ex = "{0}: {1} == {2}"; + ex = MessageFormat.format(ex, msg, value1, value2); + this.exception.expectMessage(ex); + + DBC.PRE.assertNotEquals(msg, value1, value2); + } + + /** + * Run the void assertExists(String,File) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertExists_1() throws Exception { + String msg = ""; + File file = new File("src"); + + DBC.PRE.assertExists(msg, file); + } + + /** + * Run the void assertExists(String,File) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertExists_2() throws Exception { + this.exception.expect(DbcException.class); + this.exception.expectMessage("Illegal situation as file (srcc) does not exist:"); + + String msg = ""; + File file = new File("srcc"); + + DBC.PRE.assertExists(msg, file); + + // add additional test code here + // An unexpected exception was thrown in user code while executing this test: + // li.strolch.utils.DBC.PRE.DBC$DbcException: Illegal situation as file () does not exist: + // at li.strolch.utils.DBC.PRE.DBC.PRE.assertExists(DBC.PRE.java:95) + } + + /** + * Run the void assertFalse(String,boolean) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertFalse_1() throws Exception { + this.exception.expect(DbcException.class); + this.exception.expectMessage("Expected false, but was true: "); + + String msg = ""; + boolean value = true; + + DBC.PRE.assertFalse(msg, value); + } + + /** + * Run the void assertFalse(String,boolean) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertFalse_2() throws Exception { + String msg = ""; + boolean value = false; + + DBC.PRE.assertFalse(msg, value); + + // add additional test code here + } + + /** + * Run the void assertNotEmpty(String,String) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEmpty_1() throws Exception { + this.exception.expect(DbcException.class); + this.exception.expectMessage("Illegal empty value: "); + + String msg = "Illegal empty value: "; + String value = ""; + + DBC.PRE.assertNotEmpty(msg, value); + } + + /** + * Run the void assertNotEmpty(String,String) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotEmpty_2() throws Exception { + String msg = ""; + String value = "a"; + + DBC.PRE.assertNotEmpty(msg, value); + } + + /** + * Run the void assertNotExists(String,File) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotExists_1() throws Exception { + String msg = ""; + File file = new File("srcc"); + + DBC.PRE.assertNotExists(msg, file); + + // add additional test code here + } + + /** + * Run the void assertNotExists(String,File) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotExists_2() throws Exception { + this.exception.expect(DbcException.class); + this.exception.expectMessage("Illegal situation as file (src) exists: "); + + String msg = ""; + File file = new File("src"); + + DBC.PRE.assertNotExists(msg, file); + + // add additional test code here + } + + /** + * Run the void assertNotNull(String,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotNull_1() throws Exception { + this.exception.expect(DbcException.class); + + String msg = ""; + Object value = null; + + String ex = "{0}: Illegal null value"; + ex = MessageFormat.format(ex, msg, value); + this.exception.expectMessage(ex); + + DBC.PRE.assertNotNull(msg, value); + } + + /** + * Run the void assertNotNull(String,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNotNull_2() throws Exception { + String msg = ""; + Object value = new Object(); + + DBC.PRE.assertNotNull(msg, value); + + // add additional test code here + } + + /** + * Run the void assertNull(String,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNull_1() throws Exception { + this.exception.expect(DbcException.class); + + Object value = new Object(); + + String msg = MessageFormat.format("{0}: {1} != null", "", value); + this.exception.expectMessage(msg); + + DBC.PRE.assertNull(msg, value); + } + + /** + * Run the void assertNull(String,Object) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertNull_2() throws Exception { + String msg = ""; + Object value = null; + + DBC.PRE.assertNull(msg, value); + + // add additional test code here + } + + /** + * Run the void assertTrue(String,boolean) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertTrue_1() throws Exception { + this.exception.expect(DbcException.class); + this.exception.expectMessage("Expected true, but was false: "); + + String msg = ""; + boolean value = false; + + DBC.PRE.assertTrue(msg, value); + + // add additional test code here + // An unexpected exception was thrown in user code while executing this test: + // li.strolch.utils.DBC.PRE.DBC$DbcException: Expected true, but was false: + // at li.strolch.utils.DBC.PRE.DBC.PRE.assertTrue(DBC.PRE.java:47) + } + + /** + * Run the void assertTrue(String,boolean) method test. + * + * @throws Exception + * + * @generatedBy CodePro at 2/2/14 8:13 PM + */ + @Test + public void testAssertTrue_2() throws Exception { + String msg = ""; + boolean value = true; + + DBC.PRE.assertTrue(msg, value); + + // add additional test code here + } +} \ No newline at end of file diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/AesCryptoHelperTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/AesCryptoHelperTest.java new file mode 100644 index 000000000..a3b01faf7 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/AesCryptoHelperTest.java @@ -0,0 +1,161 @@ +package li.strolch.utils.helper; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.AesCryptoHelper; +import li.strolch.utils.helper.ExceptionHelper; +import li.strolch.utils.helper.FileHelper; +import li.strolch.utils.helper.StringHelper; + +public class AesCryptoHelperTest { + + private static final Logger logger = LoggerFactory.getLogger(AesCryptoHelperTest.class); + + private static final char[] password = "A2589309-17AE-4819-B9E4-E577CFA7778F".toCharArray(); + private static final byte[] salt; + + static { + try { + salt = "E68761B3-4E8E-4122-9B12-8B89E0AEB233".getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + @Test + public void shouldWrapStreams() throws Exception { + + try { + byte[] clearTextBytes = "Some text".getBytes(); + + // encrypt data + ByteArrayOutputStream encryptedOut = new ByteArrayOutputStream(); + try (OutputStream outputStream = AesCryptoHelper.wrapEncrypt(password, salt, encryptedOut)) { + outputStream.write(clearTextBytes); + outputStream.flush(); + } + + // decrypt data + byte[] encryptedBytes = encryptedOut.toByteArray(); + ByteArrayInputStream encryptedIn = new ByteArrayInputStream(encryptedBytes); + try (InputStream inputStream = AesCryptoHelper.wrapDecrypt(password, salt, encryptedIn)) { + + ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream(); + byte[] readBuffer = new byte[64]; + int read = 0; + while ((read = inputStream.read(readBuffer)) != -1) { + decryptedOut.write(readBuffer, 0, read); + } + + byte[] decryptedBytes = decryptedOut.toByteArray(); + assertArrayEquals(clearTextBytes, decryptedBytes); + } + + } catch (RuntimeException e) { + if (ExceptionHelper.getRootCause(e).getMessage().equals("Illegal key size or default parameters")) + logger.warn("YOU ARE MISSING THE UNLIMITED JCE POLICIES and can not do AES encryption!"); + else + throw e; + } + } + + @Test + public void shouldEncryptBytes() { + try { + + byte[] clearTextBytes = "Some text".getBytes(); + + byte[] encryptedBytes = AesCryptoHelper.encrypt(password, salt, clearTextBytes); + byte[] decryptedBytes = AesCryptoHelper.decrypt(password, salt, encryptedBytes); + + assertArrayEquals(clearTextBytes, decryptedBytes); + + } catch (RuntimeException e) { + if (ExceptionHelper.getRootCause(e).getMessage().equals("Illegal key size or default parameters")) + logger.warn("YOU ARE MISSING THE UNLIMITED JCE POLICIES and can not do AES encryption!"); + else + throw e; + } + } + + @Test + public void shouldEncryptShortFile() { + // file to be encrypted + String clearTextFileS = "src/test/resources/crypto_test_short.txt"; + // encrypted file + String encryptedFileS = "target/encrypted_short.aes"; + // encrypted file + String decryptedFileS = "target/decrypted_short.txt"; + + testCrypto(clearTextFileS, encryptedFileS, decryptedFileS); + } + + @Test + public void shouldEncryptMiddleFile() { + // file to be encrypted + String clearTextFileS = "src/test/resources/crypto_test_middle.txt"; + // encrypted file + String encryptedFileS = "target/encrypted_middle.aes"; + // encrypted file + String decryptedFileS = "target/decrypted_middle.txt"; + + testCrypto(clearTextFileS, encryptedFileS, decryptedFileS); + } + + @Test + public void shouldEncryptLongFile() { + // file to be encrypted + String clearTextFileS = "src/test/resources/crypto_test_long.txt"; + // encrypted file + String encryptedFileS = "target/encrypted_long.aes"; + // encrypted file + String decryptedFileS = "target/decrypted_long.txt"; + + testCrypto(clearTextFileS, encryptedFileS, decryptedFileS); + } + + @Test + public void shouldEncryptBinaryFile() { + + // file to be encrypted + String clearTextFileS = "src/test/resources/crypto_test_image.ico"; + // encrypted file + String encryptedFileS = "target/encrypted_image.aes"; + // encrypted file + String decryptedFileS = "target/decrypted_image.ico"; + + testCrypto(clearTextFileS, encryptedFileS, decryptedFileS); + + } + + private static void testCrypto(String clearTextFileS, String encryptedFileS, String decryptedFileS) { + try { + + AesCryptoHelper.encrypt(password, salt, clearTextFileS, encryptedFileS); + AesCryptoHelper.decrypt(password, salt, encryptedFileS, decryptedFileS); + + String inputSha256 = StringHelper.getHexString(FileHelper.hashFileSha256(new File(clearTextFileS))); + String doutputSha256 = StringHelper.getHexString(FileHelper.hashFileSha256(new File(decryptedFileS))); + + assertEquals(inputSha256, doutputSha256); + + } catch (RuntimeException e) { + if (ExceptionHelper.getRootCause(e).getMessage().equals("Illegal key size or default parameters")) + logger.warn("YOU ARE MISSING THE UNLIMITED JCE POLICIES and can not do AES encryption!"); + else + throw e; + } + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/BaseDecodingTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/BaseDecodingTest.java new file mode 100644 index 000000000..d261037af --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/BaseDecodingTest.java @@ -0,0 +1,195 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import static li.strolch.utils.helper.BaseEncoding.fromBase16; +import static li.strolch.utils.helper.BaseEncoding.fromBase32; +import static li.strolch.utils.helper.BaseEncoding.fromBase32Dmedia; +import static li.strolch.utils.helper.BaseEncoding.fromBase32Hex; +import static li.strolch.utils.helper.BaseEncoding.fromBase64; +import static li.strolch.utils.helper.BaseEncoding.toBase32Hex; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.PropertiesHelper; +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class BaseDecodingTest { + public static final String PROP_RUN_PERF_TESTS = "li.strolch.utils.test.runPerfTests"; //$NON-NLS-1$ + private static final Logger logger = LoggerFactory.getLogger(BaseDecodingTest.class); + + public static boolean isSkipPerfTests() { + String context = BaseDecodingTest.class.getSimpleName(); + String key = PROP_RUN_PERF_TESTS; + boolean runPerfTests = PropertiesHelper.getPropertyBool(context, key, Boolean.FALSE); + return !runPerfTests; + } + + @Test + public void testBase64() { + assertEquals("", fromBase64("")); + assertEquals("f", fromBase64("Zg==")); + assertEquals("fo", fromBase64("Zm8=")); + assertEquals("foo", fromBase64("Zm9v")); + assertEquals("foob", fromBase64("Zm9vYg==")); + assertEquals("fooba", fromBase64("Zm9vYmE=")); + assertEquals("foobar", fromBase64("Zm9vYmFy")); + } + + @Test + public void testBase32() { + assertEquals("", fromBase32("")); + assertEquals("f", fromBase32("MY======")); + assertEquals("fo", fromBase32("MZXQ====")); + assertEquals("foo", fromBase32("MZXW6===")); + assertEquals("foob", fromBase32("MZXW6YQ=")); + assertEquals("fooba", fromBase32("MZXW6YTB")); + assertEquals("foobar", fromBase32("MZXW6YTBOI======")); + } + + @Test + public void testBase32Hex() { + assertEquals("", fromBase32Hex("")); + assertEquals("f", fromBase32Hex("CO======")); + assertEquals("fo", fromBase32Hex("CPNG====")); + assertEquals("foo", fromBase32Hex("CPNMU===")); + assertEquals("foob", fromBase32Hex("CPNMUOG=")); + assertEquals("fooba", fromBase32Hex("CPNMUOJ1")); + assertEquals("foobar", fromBase32Hex("CPNMUOJ1E8======")); + } + + @Test + public void testBase32Dmedia() { + + assertEquals("", fromBase32Dmedia("")); + assertEquals("binary foo", fromBase32Dmedia("FCNPVRELI7J9FUUI")); + assertEquals("f", fromBase32Dmedia("FR======")); + assertEquals("fo", fromBase32Dmedia("FSQJ====")); + assertEquals("foo", fromBase32Dmedia("FSQPX===")); + assertEquals("foob", fromBase32Dmedia("FSQPXRJ=")); + assertEquals("fooba", fromBase32Dmedia("FSQPXRM4")); + assertEquals("foobar", fromBase32Dmedia("FSQPXRM4HB======")); + } + + @Test + public void testBase16() { + assertEquals("", fromBase16("")); + assertEquals("f", fromBase16("66")); + assertEquals("fo", fromBase16("666F")); + assertEquals("foo", fromBase16("666F6F")); + assertEquals("foob", fromBase16("666F6F62")); + assertEquals("fooba", fromBase16("666F6F6261")); + assertEquals("foobar", fromBase16("666F6F626172")); + } + + @Test + public void testBase64Perf() { + if (isSkipPerfTests()) { + return; + } + + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = 'Z'; + } + long start = System.nanoTime(); + for (int i = 0; i < 200; i++) { + fromBase64(bytes); + } + long end = System.nanoTime(); + logger.info("Decoding 200MB Base64 took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase32Perf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = 'M'; + } + long start = System.nanoTime(); + for (int i = 0; i < 200; i++) { + fromBase32(bytes); + } + long end = System.nanoTime(); + logger.info("Decoding 200MB Base32 took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase32HexPerf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = 'C'; + } + long start = System.nanoTime(); + for (int i = 0; i < 200; i++) { + fromBase32Hex(bytes); + } + long end = System.nanoTime(); + logger.info("Decoding 200MB Base32Hex took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase32DmediaPerf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + long start = System.nanoTime(); + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < 200; i++) { + toBase32Hex(bytes); + } + long end = System.nanoTime(); + logger.info("Encoding 200MB Base32Dmedia took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase16Perf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = '6'; + } + long start = System.nanoTime(); + for (int i = 0; i < 200; i++) { + fromBase16(bytes); + } + long end = System.nanoTime(); + logger.info("Decoding 200MB Base16 took " + StringHelper.formatNanoDuration(end - start)); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/BaseEncodingTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/BaseEncodingTest.java new file mode 100644 index 000000000..00398110c --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/BaseEncodingTest.java @@ -0,0 +1,176 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import static li.strolch.utils.helper.BaseDecodingTest.PROP_RUN_PERF_TESTS; +import static li.strolch.utils.helper.BaseDecodingTest.isSkipPerfTests; +import static li.strolch.utils.helper.BaseEncoding.toBase16; +import static li.strolch.utils.helper.BaseEncoding.toBase32; +import static li.strolch.utils.helper.BaseEncoding.toBase32Dmedia; +import static li.strolch.utils.helper.BaseEncoding.toBase32Hex; +import static li.strolch.utils.helper.BaseEncoding.toBase64; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.StringHelper; + +/** + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class BaseEncodingTest { + + private static final Logger logger = LoggerFactory.getLogger(BaseEncodingTest.class); + + @Test + public void testBase64() { + assertEquals("", toBase64("")); + assertEquals("Zg==", toBase64("f")); + assertEquals("Zm8=", toBase64("fo")); + assertEquals("Zm9v", toBase64("foo")); + assertEquals("Zm9vYg==", toBase64("foob")); + assertEquals("Zm9vYmE=", toBase64("fooba")); + assertEquals("Zm9vYmFy", toBase64("foobar")); + } + + @Test + public void testBase32() { + assertEquals("", toBase32("")); + assertEquals("MY======", toBase32("f")); + assertEquals("MZXQ====", toBase32("fo")); + assertEquals("MZXW6===", toBase32("foo")); + assertEquals("MZXW6YQ=", toBase32("foob")); + assertEquals("MZXW6YTB", toBase32("fooba")); + assertEquals("MZXW6YTBOI======", toBase32("foobar")); + } + + @Test + public void testBase32Hex() { + assertEquals("", toBase32Hex("")); + assertEquals("CO======", toBase32Hex("f")); + assertEquals("CPNG====", toBase32Hex("fo")); + assertEquals("CPNMU===", toBase32Hex("foo")); + assertEquals("CPNMUOG=", toBase32Hex("foob")); + assertEquals("CPNMUOJ1", toBase32Hex("fooba")); + assertEquals("CPNMUOJ1E8======", toBase32Hex("foobar")); + } + + @Test + public void testBase32Dmedia() { + assertEquals("", toBase32Dmedia("")); + assertEquals("FCNPVRELI7J9FUUI", toBase32Dmedia("binary foo")); + assertEquals("FR======", toBase32Dmedia("f")); + assertEquals("FSQJ====", toBase32Dmedia("fo")); + assertEquals("FSQPX===", toBase32Dmedia("foo")); + assertEquals("FSQPXRJ=", toBase32Dmedia("foob")); + assertEquals("FSQPXRM4", toBase32Dmedia("fooba")); + assertEquals("FSQPXRM4HB======", toBase32Dmedia("foobar")); + } + + @Test + public void testBase16() { + assertEquals("", toBase16("")); + assertEquals("66", toBase16("f")); + assertEquals("666F", toBase16("fo")); + assertEquals("666F6F", toBase16("foo")); + assertEquals("666F6F62", toBase16("foob")); + assertEquals("666F6F6261", toBase16("fooba")); + assertEquals("666F6F626172", toBase16("foobar")); + } + + @Test + public void testBase64Perf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + long start = System.nanoTime(); + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < 200; i++) { + toBase64(bytes); + } + long end = System.nanoTime(); + logger.info("Encoding 200MB Base64 took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase32Perf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + long start = System.nanoTime(); + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < 200; i++) { + toBase32(bytes); + } + long end = System.nanoTime(); + logger.info("Encoding 200MB Base32 took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase32HexPerf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + long start = System.nanoTime(); + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < 200; i++) { + toBase32Hex(bytes); + } + long end = System.nanoTime(); + logger.info("Encoding 200MB Base32Hex took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase32DmediaPerf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + long start = System.nanoTime(); + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < 200; i++) { + toBase32Hex(bytes); + } + long end = System.nanoTime(); + logger.info("Encoding 200MB Base32Dmedia took " + StringHelper.formatNanoDuration(end - start)); + } + + @Test + public void testBase16Perf() { + if (isSkipPerfTests()) { + logger.info("Not running performance tests as not enabled by system property " + PROP_RUN_PERF_TESTS); + return; + } + + long start = System.nanoTime(); + byte[] bytes = new byte[1024 * 1024]; + for (int i = 0; i < 200; i++) { + toBase16(bytes); + } + long end = System.nanoTime(); + logger.info("Encoding 200MB Base16 took " + StringHelper.formatNanoDuration(end - start)); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/ExceptionHelperTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/ExceptionHelperTest.java new file mode 100644 index 000000000..5cdfec029 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/ExceptionHelperTest.java @@ -0,0 +1,48 @@ +package li.strolch.utils.helper; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import li.strolch.utils.helper.ExceptionHelper; + +public class ExceptionHelperTest { + + @Test + public void shouldGetExceptionMsg() { + + Exception e = nestedException(); + assertEquals("Third", ExceptionHelper.getExceptionMessage(e)); + assertEquals("Third\nSecond\nFirst", ExceptionHelper.getExceptionMessageWithCauses(e)); + } + + @Test + public void shouldFormatException() { + + Exception e = nestedException(); + String formatException = ExceptionHelper.formatException(e); + assertTrue(formatException.contains("java.lang.RuntimeException: First")); + assertTrue(formatException.contains("java.lang.RuntimeException: Second")); + assertTrue(formatException.contains("java.lang.RuntimeException: Third")); + + formatException = ExceptionHelper.formatExceptionMessage(e); + assertEquals("Third\ncause:\nSecond\ncause:\nFirst", formatException); + } + + private Exception nestedException() { + try { + try { + try { + throw new RuntimeException("First"); + } catch (Exception e) { + throw new RuntimeException("Second", e); + } + } catch (Exception e) { + throw new RuntimeException("Third", e); + } + } catch (Exception e) { + return e; + } + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/GenerateReverseBaseEncodingAlphabets.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/GenerateReverseBaseEncodingAlphabets.java new file mode 100644 index 000000000..dc4ab50e4 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/GenerateReverseBaseEncodingAlphabets.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.helper; + +import java.util.HashMap; +import java.util.Map; + +import li.strolch.utils.helper.BaseEncoding; + +/** + * Simple helper class to generate the reverse alphabets for {@link BaseEncoding} + * + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class GenerateReverseBaseEncodingAlphabets { + + public static void main(String[] args) { + + System.out.println(generateReverseAlphabet("REV_BASE_16", BaseEncoding.BASE_16)); + System.out.println(generateReverseAlphabet("REV_BASE_32", BaseEncoding.BASE_32)); + System.out.println(generateReverseAlphabet("REV_BASE_32_CROCKFORD", BaseEncoding.BASE_32_CROCKFORD)); + System.out.println(generateReverseAlphabet("REV_BASE_32_DMEDIA", BaseEncoding.BASE_32_DMEDIA)); + System.out.println(generateReverseAlphabet("REV_BASE_32_HEX", BaseEncoding.BASE_32_HEX)); + System.out.println(generateReverseAlphabet("REV_BASE_64", BaseEncoding.BASE_64)); + System.out.println(generateReverseAlphabet("REV_BASE_64_SAFE", BaseEncoding.BASE_64_SAFE)); + } + + public static String generateReverseAlphabet(String name, byte[] alphabet) { + + Map valueToIndex = new HashMap<>(); + for (byte i = 0; i < alphabet.length; i++) { + Byte value = Byte.valueOf(i); + Byte key = Byte.valueOf(alphabet[value]); + if (valueToIndex.containsKey(key)) + throw new RuntimeException("Alphabet hast twice the same value " + key + " at index " + value); + valueToIndex.put(key, value); + } + + StringBuilder sb = new StringBuilder(); + sb.append("private static final byte[] " + name + " = { "); + + Byte minusOne = Byte.valueOf((byte) -1); + for (int i = 0; i < 128; i++) { + Byte index = Byte.valueOf((byte) i); + Byte value = valueToIndex.get(index); + if (value == null) + sb.append(minusOne.toString()); + else + sb.append(value.toString()); + + if (i < 127) + sb.append(", "); + } + + sb.append(" };"); + + return sb.toString(); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/ReplacePropertiesInTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/ReplacePropertiesInTest.java new file mode 100644 index 000000000..9d75b685f --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/ReplacePropertiesInTest.java @@ -0,0 +1,140 @@ +package li.strolch.utils.helper; + +import static org.junit.Assert.assertEquals; + +import java.util.Properties; + +import org.junit.Test; + +import li.strolch.utils.helper.StringHelper; + +public class ReplacePropertiesInTest { + + @Test + public void shouldReplaceProps1() { + + String expr = "bla ${foo}"; + String expected = "bla bar"; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps2() { + + String expr = "${foo} bla "; + String expected = "bar bla "; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps3() { + + String expr = "bla ${foo} "; + String expected = "bla bar "; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps4() { + + String expr = "bla${foo}abr"; + String expected = "blabarabr"; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps5() { + + String expr = "bla '${foo}' "; + String expected = "bla 'bar' "; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps6() { + + String expr = "${foo}bla ${foo} "; + String expected = "barbla bar "; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps7() { + + String expr = "${foo}bla ${food} "; + String expected = "barbla foofoo "; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + properties.setProperty("food", "foofoo"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps8() { + + String expr = "foo"; + String expected = "foo"; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + + String result = StringHelper.replacePropertiesIn(properties, expr); + + assertEquals(expected, result); + } + + @Test + public void shouldReplaceProps9() { + + String expr = "%{foo}bla %{food} "; + String expected = "barbla foofoo "; + + Properties properties = new Properties(); + properties.setProperty("foo", "bar"); + properties.setProperty("food", "foofoo"); + + String result = StringHelper.replacePropertiesIn(properties, '%', expr); + + assertEquals(expected, result); + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/helper/XmlSignHelperTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/helper/XmlSignHelperTest.java new file mode 100644 index 000000000..14f339c82 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/helper/XmlSignHelperTest.java @@ -0,0 +1,208 @@ +package li.strolch.utils.helper; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; + +import javax.xml.crypto.dsig.XMLSignature; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import li.strolch.utils.helper.XmlDomSigner; + +public class XmlSignHelperTest { + + private static XmlDomSigner helper; + + @BeforeClass + public static void beforeClass() { + helper = new XmlDomSigner(new File("src/test/resources/test.jks"), "client", "server", + "changeit".toCharArray()); + } + + @Test + public void shouldSign() { + Document document = createDoc(); + helper.sign(document); + + assertSignatureElemExists(document); + } + + @Test + public void shouldSignWithNamespaces() { + + Document document = createDocWithNamespaces(); + + // hack for signing with namespaces problem + document = XmlDomSigner.parse(XmlDomSigner.transformToBytes(document)); + + helper.sign(document); + + assertSignatureElemExists(document); + } + + private void assertSignatureElemExists(Document document) { + NodeList nl = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); + assertEquals("Expected exactly one Signature element!", 1, nl.getLength()); + } + + @Test + public void shouldValidate() { + + File signedXmlFile = new File("src/test/resources/SignedXmlFile.xml"); + Document document = XmlDomSigner.parse(signedXmlFile); + setIdAttr(document); + helper.validate(document); + } + + @Test + public void shouldValidateWithNamespaces() { + + File signedXmlFile = new File("src/test/resources/SignedXmlFileWithNamespaces.xml"); + Document document = XmlDomSigner.parse(signedXmlFile); + setIdAttrNs(document); + + helper.validate(document); + } + + private void setIdAttr(Document document) { + NodeList authnRequestNodes = document.getElementsByTagName("AuthnRequest"); + if (authnRequestNodes.getLength() != 1) + throw new IllegalStateException("Multiple or no AuthnRequest Node found in document!"); + Element authnRequestNode = (Element) authnRequestNodes.item(0); + authnRequestNode.setIdAttribute("ID", true); + } + + private void setIdAttrNs(Document document) { + NodeList authnRequestNodes = document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:protocol", + "AuthnRequest"); + if (authnRequestNodes.getLength() != 1) + throw new IllegalStateException("Multiple or no AuthnRequest Node found in document!"); + Element authnRequestNode = (Element) authnRequestNodes.item(0); + authnRequestNode.setIdAttribute("ID", true); + } + + @Test + public void shouldSignAndValidate() { + + Document document = createDoc(); + + helper.sign(document); + helper.validate(document); + } + + @Test + public void shouldSignAndValidateWithNamespaces() { + + Document document = createDocWithNamespaces(); + + // hack for signing with namespaces problem + document = XmlDomSigner.parse(XmlDomSigner.transformToBytes(document)); + + helper.sign(document); + helper.validate(document); + } + + public static Document createDoc() { + + String issuer = "test"; + String destination = "test"; + String assertionConsumerServiceUrl = "test"; + Calendar issueInstant = Calendar.getInstance(); + + // create dates + SimpleDateFormat simpleDf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + simpleDf.setTimeZone(TimeZone.getTimeZone("UTC")); + String issueInstantS = simpleDf.format(issueInstant.getTime()); + String notBeforeS = issueInstantS; + issueInstant.add(Calendar.SECOND, 10); + String notOnOrAfterS = simpleDf.format(issueInstant.getTime()); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder docBuilder; + try { + docBuilder = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new RuntimeException("Failed to configure document builder!", e); + } + Document doc = docBuilder.newDocument(); + + Element authnReqE = doc.createElement("AuthnRequest"); + authnReqE.setAttribute("Version", "2.0"); + authnReqE.setAttribute("IssueInstant", issueInstantS); + authnReqE.setAttribute("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"); + authnReqE.setAttribute("AssertionConsumerServiceURL", assertionConsumerServiceUrl); + authnReqE.setAttribute("Destination", destination); + doc.appendChild(authnReqE); + + Element issuerE = doc.createElement("Issuer"); + issuerE.setTextContent(issuer); + authnReqE.appendChild(issuerE); + + Element conditionsE = doc.createElement("Conditions"); + conditionsE.setAttribute("NotBefore", notBeforeS); + conditionsE.setAttribute("NotOnOrAfter", notOnOrAfterS); + authnReqE.appendChild(conditionsE); + + return doc; + } + + public static Document createDocWithNamespaces() { + + String issuer = "test"; + String destination = "test"; + String assertionConsumerServiceUrl = "test"; + Calendar issueInstant = Calendar.getInstance(); + + // create dates + SimpleDateFormat simpleDf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + simpleDf.setTimeZone(TimeZone.getTimeZone("UTC")); + String issueInstantS = simpleDf.format(issueInstant.getTime()); + String notBeforeS = issueInstantS; + issueInstant.add(Calendar.SECOND, 10); + String notOnOrAfterS = simpleDf.format(issueInstant.getTime()); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder docBuilder; + try { + docBuilder = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new RuntimeException("Failed to configure document builder!", e); + } + Document doc = docBuilder.newDocument(); + + Element authnReqE = doc.createElementNS("urn:oasis:names:tc:SAML:2.0:protocol", "AuthnRequest"); + authnReqE.setPrefix("samlp"); + authnReqE.setAttribute("Version", "2.0"); + authnReqE.setAttribute("IssueInstant", issueInstantS); + authnReqE.setAttribute("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"); + authnReqE.setAttribute("AssertionConsumerServiceURL", assertionConsumerServiceUrl); + authnReqE.setAttribute("Destination", destination); + doc.appendChild(authnReqE); + + Element issuerE = doc.createElementNS("urn:oasis:names:tc:SAML:2.0:assertion", "Issuer"); + issuerE.setPrefix("saml"); + issuerE.setTextContent(issuer); + authnReqE.appendChild(issuerE); + + Element conditionsE = doc.createElementNS("urn:oasis:names:tc:SAML:2.0:assertion", "Conditions"); + conditionsE.setPrefix("saml"); + conditionsE.setAttribute("NotBefore", notBeforeS); + conditionsE.setAttribute("NotOnOrAfter", notOnOrAfterS); + authnReqE.appendChild(conditionsE); + + return doc; + } +} diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/objectfilter/ObjectFilterTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/objectfilter/ObjectFilterTest.java new file mode 100644 index 000000000..33b81fe89 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/objectfilter/ObjectFilterTest.java @@ -0,0 +1,437 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.utils.objectfilter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.List; + +import org.junit.Test; + +import li.strolch.utils.objectfilter.ObjectFilter; + +/** + * @author Robert von Burg + */ +@SuppressWarnings("nls") +public class ObjectFilterTest { + + @Test + public void shouldAdd() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj); + + testAssertions(filter, 1, 1, 1, 0, 0); + } + + @Test + public void shouldUpdate() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.update(myObj); + + testAssertions(filter, 1, 1, 0, 1, 0); + } + + @Test + public void shouldRemove() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.remove(myObj); + + testAssertions(filter, 1, 1, 0, 0, 1); + } + + @Test + public void shouldAddUpdateRemoveDifferentObjects() { + + Object objToAdd = new Object(); + Object objToUpdate = new Object(); + Object objToRemove = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(objToAdd); + filter.update(objToUpdate); + filter.remove(objToRemove); + + testAssertions(filter, 3, 1, 1, 1, 1); + } + + @Test + public void shouldAddUpdateRemoveSameObject() { + + Object objToAddUpdateRemove = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(objToAddUpdateRemove); + filter.update(objToAddUpdateRemove); + filter.remove(objToAddUpdateRemove); + + testAssertions(filter, 0, 1, 0, 0, 0); + } + + @Test + public void shouldNotAddTwice() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj); + + try { + filter.add(myObj); + fail("Should have failed adding twice!"); + } catch (RuntimeException e) { + assertEquals("Stale State exception: Invalid + after +", e.getMessage()); + } + + testAssertions(filter, 1, 1, 1, 0, 0); + } + + @Test + public void shouldNotRemoveTwice() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.remove(myObj); + + try { + filter.remove(myObj); + fail("Should have failed removing twice!"); + } catch (RuntimeException e) { + assertEquals("Stale State exception: Invalid - after -", e.getMessage()); + } + + testAssertions(filter, 1, 1, 0, 0, 1); + } + + @Test + public void shouldAcceptUpdateTwice() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.update(myObj); + filter.update(myObj); + testAssertions(filter, 1, 1, 0, 1, 0); + } + + @Test + public void shouldStillBeAddWithUpdate() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj); + filter.update(myObj); + filter.update(myObj); + testAssertions(filter, 1, 1, 1, 0, 0); + } + + @Test + public void shouldNotAcceptAddAfterModify() { + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.update(myObj); + + try { + filter.add(myObj); + fail("Should have failed add after modify"); + } catch (RuntimeException e) { + assertEquals("Stale State exception: Invalid + after +=", e.getMessage()); + } + + testAssertions(filter, 1, 1, 0, 1, 0); + } + + @Test + public void shouldAcceptAddAfterRemove() { + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.remove(myObj); + filter.add(myObj); + + testAssertions(filter, 1, 1, 0, 1, 0); + } + + @Test + public void shouldNotAcceptModifyAfterRemove() { + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.remove(myObj); + + try { + filter.update(myObj); + fail("Should have failed modify after remove"); + } catch (RuntimeException e) { + assertEquals("Stale State exception: Invalid += after -", e.getMessage()); + } + + testAssertions(filter, 1, 1, 0, 0, 1); + } + + @Test + public void shouldNotAcceptDifferentKeyForSameObject() { + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj); + + try { + filter.update("different_key", myObj); + fail("Should have failed because of different key for already registered object"); + } catch (RuntimeException e) { + String msg = "Object may be present in the same filter instance only once, registered using one key only"; + assertTrue("Encountered exception: " + e.getMessage(), e.getMessage().contains(msg)); + } + + testAssertions(filter, 1, 1, 1, 0, 0); + } + + @Test + public void shouldReplaceOnAddAfterRemove() { + + TestObject obj1 = new TestObject(1); + TestObject obj2 = new TestObject(1); + assertEquals("Test objects are not equal!", obj1, obj2); + + ObjectFilter filter = new ObjectFilter(); + filter.remove(Object.class.getName(), obj1); + filter.add(Object.class.getName(), obj2); + + testAssertions(filter, 1, 1, 0, 1, 0); + + List updated = filter.getUpdated(Object.class.getName()); + Object updatedObj = updated.get(0); + String msg = "registered object is not the last operation's object"; + assertTrue(msg, obj2 == updatedObj); + } + + @Test + public void shouldReplaceOnUpdateAfterAdd() { + + TestObject obj1 = new TestObject(1); + TestObject obj2 = new TestObject(1); + assertEquals("Test objects are not equal!", obj1, obj2); + + ObjectFilter filter = new ObjectFilter(); + filter.add(Object.class.getName(), obj1); + filter.update(Object.class.getName(), obj2); + + testAssertions(filter, 1, 1, 1, 0, 0); + + List added = filter.getAdded(Object.class.getName()); + Object addedObj = added.get(0); + String msg = "registered object is not the last operation's object"; + assertTrue(msg, obj2 == addedObj); + } + + @Test + public void shouldReplaceOnUpdateAfterUpdate() { + + TestObject obj1 = new TestObject(1); + TestObject obj2 = new TestObject(1); + assertEquals("Test objects are not equal!", obj1, obj2); + + ObjectFilter filter = new ObjectFilter(); + filter.update(Object.class.getName(), obj1); + filter.update(Object.class.getName(), obj2); + + testAssertions(filter, 1, 1, 0, 1, 0); + + List updated = filter.getUpdated(Object.class.getName()); + Object updatedObj = updated.get(0); + String msg = "registered object is not the last operation's object"; + assertTrue(msg, obj2 == updatedObj); + } + + @Test + public void shouldReplaceOnRemoveAfterModify() { + + TestObject obj1 = new TestObject(1); + TestObject obj2 = new TestObject(1); + assertEquals("Test objects are not equal!", obj1, obj2); + + ObjectFilter filter = new ObjectFilter(); + filter.update(Object.class.getName(), obj1); + filter.remove(Object.class.getName(), obj2); + + testAssertions(filter, 1, 1, 0, 0, 1); + + List removed = filter.getRemoved(Object.class.getName()); + Object removedObj = removed.get(0); + String msg = "registered object is not the last operation's object"; + assertTrue(msg, obj2 == removedObj); + } + + @Test + public void shouldRemoveAfterAddAndRemove() { + + Object myObj = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj); + filter.remove(myObj); + testAssertions(filter, 0, 1, 0, 0, 0); + } + + @Test + public void shouldClear() { + + Object myObj1 = new Object(); + Object myObj2 = new Object(); + Object myObj3 = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj1); + filter.update(myObj2); + filter.remove(myObj3); + + filter.clearCache(); + + testAssertions(filter, 0, 0, 0, 0, 0); + } + + @Test + public void shouldGetAll() { + + Object myObj1 = new Object(); + Object myObj2 = new Object(); + Object myObj3 = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj1); + filter.update(myObj2); + filter.remove(myObj3); + + testAssertions(filter, 3, 1, 1, 1, 1); + + List all = filter.getAll(Object.class.getName()); + assertEquals(3, all.size()); + assertTrue(all.contains(myObj1)); + assertTrue(all.contains(myObj2)); + assertTrue(all.contains(myObj3)); + } + + @Test + public void shouldGetAdded() { + + Object myObj1 = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.add(myObj1); + + testAssertions(filter, 1, 1, 1, 0, 0); + + List list = filter.getAdded(Object.class.getName()); + assertEquals(1, list.size()); + assertTrue(list.contains(myObj1)); + } + + @Test + public void shouldGetUpdated() { + + Object myObj1 = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.update(myObj1); + + testAssertions(filter, 1, 1, 0, 1, 0); + + List list = filter.getUpdated(Object.class.getName()); + assertEquals(1, list.size()); + assertTrue(list.contains(myObj1)); + } + + @Test + public void shouldGetRemoved() { + + Object myObj1 = new Object(); + + ObjectFilter filter = new ObjectFilter(); + filter.remove(myObj1); + + testAssertions(filter, 1, 1, 0, 0, 1); + + List list = filter.getRemoved(Object.class.getName()); + assertEquals(1, list.size()); + assertTrue(list.contains(myObj1)); + } + + private void testAssertions(ObjectFilter filter, int size, int sizeKeySet, int added, int updated, int removed) { + assertEquals(size, filter.sizeCache()); + assertEquals(sizeKeySet, filter.sizeKeySet()); + + List addedList = filter.getAdded(Object.class.getName()); + assertEquals(added, addedList.size()); + + List updatedList = filter.getUpdated(Object.class.getName()); + assertEquals(updated, updatedList.size()); + + List removedList = filter.getRemoved(Object.class.getName()); + assertEquals(removed, removedList.size()); + } + + private class TestObject { + private int id; + + public TestObject(int id) { + this.id = id; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + this.id; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TestObject other = (TestObject) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (this.id != other.id) + return false; + return true; + } + + private ObjectFilterTest getOuterType() { + return ObjectFilterTest.this; + } + } +} diff --git a/li.strolch.utils/src/test/resources/SignedXmlFile.xml b/li.strolch.utils/src/test/resources/SignedXmlFile.xml new file mode 100644 index 000000000..7055600a5 --- /dev/null +++ b/li.strolch.utils/src/test/resources/SignedXmlFile.xml @@ -0,0 +1,20 @@ +test6bxgcmypqGyvyQFgEqdOk1zLTOg=RAWnchzzSHwi84ZJcog6OnkYrGx7rBGBHDsysn1lmP05+AydKzcK7Jw3kbpkGnaaz1DIV/8A/hhA +UmOjwAl8RNygtziXuS5fZfvDUidhPugv2EUKeUkH7CwMkLSB5TONC+AS8eEhfyZbl/4GYMd4Jcqx +OQJgBRMNT6zfybFY+wfJDceFUqCCmyXFgcGBmtSjJqQivwH4B8k1ui49hO67ItCBcCo0aKpqoIxF +UA2IZCDvmrdR/qCq/oA9ssjUzpC+yJMvwPtZ6LDdoWt+MDzDBkCKA6lKUqtU51rZ8GwoRLve8FXH +vCG/ZiqxKn4JwBQL2DiFuZVXhrrMvLpYyi4ZRA==CN=test,OU=li.strolch.utils,O=li.strolch,L=Solothurn,ST=Solothurn,C=CHMIIDizCCAnOgAwIBAgIEPPVdzDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJDSDESMBAGA1UE +CBMJU29sb3RodXJuMRIwEAYDVQQHEwlTb2xvdGh1cm4xFDASBgNVBAoTC2NoLmVpdGNobmV0MRow +GAYDVQQLExFjaC5laXRjaG5ldC51dGlsczENMAsGA1UEAxMEdGVzdDAeFw0xNjAzMDMxMzEwMTRa +Fw0xNjA2MDExMzEwMTRaMHYxCzAJBgNVBAYTAkNIMRIwEAYDVQQIEwlTb2xvdGh1cm4xEjAQBgNV +BAcTCVNvbG90aHVybjEUMBIGA1UEChMLY2guZWl0Y2huZXQxGjAYBgNVBAsTEWNoLmVpdGNobmV0 +LnV0aWxzMQ0wCwYDVQQDEwR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxW8E +F/odm00xQTRQ95b9RtpmiQo3OQfpkE344vyp48BpOHMm8Q+sjTHde6hGUQQ3FSp6jUZtJBmuXDp+ +hFa4zNp1vleASqmUw4VCZZN1BgHx6coWA1zw/GWyCOFHvr+JTP6/LAfemudOnQVWKx6/NkMEgjNm +OR3qsbfj1km/VlfnIAOG9SvFvydp+Jan7y+nIKllEEXpcQFeiWouvC572aptu9k9qe43mRoQHJ96 +IngJHLONi27SBsF31ipvoHjkYEaTYfv8Izf5wt7h+8tZipFHu0+5r7LbZDRhSWzopC5KZakgVgLG +0JYEzcLotOCf9hmDDZZAAv3OyLoMqN8F0QIDAQABoyEwHzAdBgNVHQ4EFgQUd38xdRA7VcrWcjmz +CYmbBMD4SaUwDQYJKoZIhvcNAQELBQADggEBACqDrXrrYG2sfFBRTIQVni291q8tDqJ1etim1fND +s9ZdYa2oKTaLjMswdlE5hVXtEvRrN+XX3TIAK0lfiDwF4E4JBDww4a3SefEbwPvx110WN6CTE1NI +P6IPCUB7e5QOlg4uKAJoZfnY6HboRiHbeOQxIeis3Q9XpqQSYrO4/NzxFt66m48BHLqf8Hwi90GY +VYMljqr+hHvUTQWGzFD3NKr9Fq6yO2GcHGc5ifmLjwoz2EDAsSubrccbN+RQRRg3II6gFxyL9PYN +HgkGjqdg3v8TiWRxWAFL2MrgNLRzOX9Sl7NMFo6JwiizfLWTgcxZZVIkcU1ZP4heXi5iKUzgsJM= \ No newline at end of file diff --git a/li.strolch.utils/src/test/resources/SignedXmlFileWithNamespaces.xml b/li.strolch.utils/src/test/resources/SignedXmlFileWithNamespaces.xml new file mode 100644 index 000000000..456b9172a --- /dev/null +++ b/li.strolch.utils/src/test/resources/SignedXmlFileWithNamespaces.xml @@ -0,0 +1,20 @@ +testKseWAs8E4H1ZGAbyl2EnlZ3RiG4=KhSDJRxo1u7eNVy1swN5RqA+37oCCeyY8QNCtT1RFz8UVZFqmXGiurscbctKA+tiYSekW4OkxEg9 +Nv03OGJcYlksdZ5CCGlsioac+NY/z2QngtlDaFudKIHwj9yZ9zMdiKT/4kdwnUQP+p9tzYV9GeA9 +gesLOielMdj382XoFQ/CIbrJevE4vpn9FSitbwHXV4kZ3/NxlBPYIgiM9yiTTT0NafFENTS38U+P +k1tL32FcDfHytWN6Twl2ZbHrRYltba/ncxaqkauMA37r9v2f+HS+hXXNluLTazRzAxnhSaetjPOt +GFP/nkG0TcRbiZFTP3YwIHeo94v2d/fs6rKHiQ==CN=test,OU=li.strolch.utils,O=li.strolch,L=Solothurn,ST=Solothurn,C=CHMIIDizCCAnOgAwIBAgIEPPVdzDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJDSDESMBAGA1UE +CBMJU29sb3RodXJuMRIwEAYDVQQHEwlTb2xvdGh1cm4xFDASBgNVBAoTC2NoLmVpdGNobmV0MRow +GAYDVQQLExFjaC5laXRjaG5ldC51dGlsczENMAsGA1UEAxMEdGVzdDAeFw0xNjAzMDMxMzEwMTRa +Fw0xNjA2MDExMzEwMTRaMHYxCzAJBgNVBAYTAkNIMRIwEAYDVQQIEwlTb2xvdGh1cm4xEjAQBgNV +BAcTCVNvbG90aHVybjEUMBIGA1UEChMLY2guZWl0Y2huZXQxGjAYBgNVBAsTEWNoLmVpdGNobmV0 +LnV0aWxzMQ0wCwYDVQQDEwR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxW8E +F/odm00xQTRQ95b9RtpmiQo3OQfpkE344vyp48BpOHMm8Q+sjTHde6hGUQQ3FSp6jUZtJBmuXDp+ +hFa4zNp1vleASqmUw4VCZZN1BgHx6coWA1zw/GWyCOFHvr+JTP6/LAfemudOnQVWKx6/NkMEgjNm +OR3qsbfj1km/VlfnIAOG9SvFvydp+Jan7y+nIKllEEXpcQFeiWouvC572aptu9k9qe43mRoQHJ96 +IngJHLONi27SBsF31ipvoHjkYEaTYfv8Izf5wt7h+8tZipFHu0+5r7LbZDRhSWzopC5KZakgVgLG +0JYEzcLotOCf9hmDDZZAAv3OyLoMqN8F0QIDAQABoyEwHzAdBgNVHQ4EFgQUd38xdRA7VcrWcjmz +CYmbBMD4SaUwDQYJKoZIhvcNAQELBQADggEBACqDrXrrYG2sfFBRTIQVni291q8tDqJ1etim1fND +s9ZdYa2oKTaLjMswdlE5hVXtEvRrN+XX3TIAK0lfiDwF4E4JBDww4a3SefEbwPvx110WN6CTE1NI +P6IPCUB7e5QOlg4uKAJoZfnY6HboRiHbeOQxIeis3Q9XpqQSYrO4/NzxFt66m48BHLqf8Hwi90GY +VYMljqr+hHvUTQWGzFD3NKr9Fq6yO2GcHGc5ifmLjwoz2EDAsSubrccbN+RQRRg3II6gFxyL9PYN +HgkGjqdg3v8TiWRxWAFL2MrgNLRzOX9Sl7NMFo6JwiizfLWTgcxZZVIkcU1ZP4heXi5iKUzgsJM= \ No newline at end of file diff --git a/li.strolch.utils/src/test/resources/crypto_test_image.ico b/li.strolch.utils/src/test/resources/crypto_test_image.ico new file mode 100644 index 000000000..b48b3442a Binary files /dev/null and b/li.strolch.utils/src/test/resources/crypto_test_image.ico differ diff --git a/li.strolch.utils/src/test/resources/crypto_test_long.txt b/li.strolch.utils/src/test/resources/crypto_test_long.txt new file mode 100644 index 000000000..80a18dc58 --- /dev/null +++ b/li.strolch.utils/src/test/resources/crypto_test_long.txt @@ -0,0 +1,447 @@ +Das Burgtheater in Wien ist ein österreichisches Bundestheater. Es gilt als eine der bedeutendsten Bühnen Europas und ist nach der Comédie-Française das zweitälteste europäische sowie das größte deutschsprachige Sprechtheater. Das alte Burgtheater befand sich seit 1748 am Michaelerplatz. Im Oktober 1888 wurde das neue Haus am heutigen Universitätsring (damals Franzensring, dann zwei andere Namen) eröffnet. Nachdem dieses 1945 infolge von Bombenangriffen vollständig ausgebrannt war, diente das Ronacher bis zur Wiedereröffnung am 14. Oktober 1955 als Ausweichquartier. Das Burgtheater gilt als österreichisches Nationaltheater.[1] + +Ältere Namen des Burgtheaters waren k.k. Theater nächst der Burg und danach bis 1918 k.k. Hof-Burgtheater. Vor allem in Wien wird es häufig kurz „Die Burg“ genannt, die Ensemblemitglieder kennt man als Burgschauspieler. Nach Zahl der Mitarbeiter und Budget ist es das „reichste und größte Repertoiretheater der Welt“.[2] Direktorin des Burgtheaters ist seit März 2014 Karin Bergmann. + +Inhaltsverzeichnis [Verbergen] +1 Geschichte +1.1 Das „alte“ Burgtheater am Michaelerplatz +1.2 Das neue Gebäude am Ring +1.3 Das Burgtheater in der Zeit des Nationalsozialismus +1.4 Das Burgtheater zu Kriegsende und nach dem Zweiten Weltkrieg +1.5 Das Burgtheater heute +1.5.1 Direktion Claus Peymann 1986–1999 +1.5.2 Direktion Klaus Bachler 1999–2009 +1.5.3 Direktion Matthias Hartmann 2009–2014 +1.5.4 Finanzskandal 2013/2014 +1.5.5 Direktion Karin Bergmann 2014 bis voraussichtlich 2019 +2 Hinter den Kulissen +2.1 Bühnentechnik und andere technische Besonderheiten +2.2 Kostüme, Requisiten +3 Weitere Spielstätten und Probebühnen des Burgtheaters +4 Die Wiener und „ihre“ Burg +4.1 Das „Burgtheaterdeutsch“ +4.2 Die großen Namen und ihre Wirkung +4.3 Ein Haus mit Tradition +4.4 Repertoire, Programm und Publikum +4.5 Abonnements, Kartenvorverkauf, Spielzeiten +4.6 Die Gesellschaft der Freunde des Burgtheaters +5 Mitarbeiter am Burgtheater +5.1 Das Ensemble +5.1.1 Derzeitige Ensemblemitglieder +5.1.2 Saison 2011/2012 +5.1.3 Ehemalige Ensemblemitglieder +5.1.4 Gastschauspieler +5.1.5 Ehrenmitglieder +5.2 Regisseure am Burgtheater +5.3 Andere Mitarbeiter +6 Anerkennung der schauspielerischen Leistung +6.1 Anerkennung der Schauspieler im Ensemble +6.2 Der Nestroy-Theaterpreis +7 Das Burgtheater im In- und Ausland +8 Die Leitung des Burgtheaters +8.1 Direktionen und künstlerische Leitungen des Burgtheaters +9 Das Burgtheater in Film und Literatur +10 Das Burgtheater im Fernsehen +11 Publikationen +12 Uraufführungen am Burgtheater (Auswahl) +13 Bildergalerie +14 Literatur +15 Weblinks +16 Einzelnachweise +Geschichte[Bearbeiten] + +Michaelerplatz mit dem alten k.k. Theater nächst der Burg (rechts) und der Winterreitschule der Hofburg (links) + +Innenraum des alten Burg­theaters, Gemälde von Gustav Klimt. Die Per­so­nen sind so detailliert dargestellt, dass die Identifizierung möglich ist. +Das „alte“ Burgtheater am Michaelerplatz[Bearbeiten] +Das ursprüngliche Burgtheater wurde in einem Ballhaus eingerichtet, das der römisch-deutsche König und spätere Kaiser Ferdinand I. 1540 im unteren Lustgarten der Hofburg erbauen ließ, nachdem das alte Ballhaus 1525 einem Brand zum Opfer gefallen war. Bis zu Beginn des 18. Jahrhunderts wurde dort das Jeu de Paume gespielt, ein Vorläufer des Tennis. Am 14. März 1741 erteilte schließlich Kaiserin Maria Theresia, die nach dem Tod ihres Vaters eine allgemeine Theatersperre angeordnet hatte, dem „Entrepreneur der königlichen Hofopern“ und Pächter des 1708 errichteten Theaters am Kärntnertor, Joseph Karl Selliers, die Erlaubnis, das Ballhaus in ein Theater umzuwandeln. Gleichzeitig wurde ein neues Ballhaus in unmittelbarer Nähe errichtet, das dem heutigen Ballhausplatz seinen Namen gab. + +Im Jahre 1748 wurde das neu gestaltete Theater nächst der Burg eröffnet. 1756 erfolgten größere Umbauarbeiten, wobei unter anderem eine neue Rückwand errichtet wurde. Der Zuschauerraum des alten Burgtheaters war noch eine reine Holzkonstruktion und fasste etwa 1200 Gäste. Die kaiserliche Familie konnte ihre Hofloge direkt von den kaiserlichen Gemächern aus erreichen, mit denen das Burgtheater baulich verbunden war. An der alten Spielstätte am Michaelerplatz wurden unter anderem mehrere Werke von Christoph Willibald Gluck, Ludwig van Beethoven, Wolfgang Amadeus Mozart sowie Franz Grillparzer uraufgeführt. + +Am 17. Februar 1776 erklärte Kaiser Joseph II. das Theater zum Teutschen Nationaltheater. Er war es auch, der per Dekret anordnete, dass die Stücke keine traurigen Ereignisse behandeln sollten, um die kaiserlichen Zuschauer in keine schlechte Stimmung zu bringen. Viele Stücke mussten deswegen geändert und mit einem Wiener Schluss (Happy End) versehen werden, beispielsweise Romeo und Julia oder Hamlet. Ab 1794 trug das Theater den Namen k.k. Hoftheater nächst der Burg. + +1798 wurde der Dichter August von Kotzebue zum Leiter des Burgtheaters ernannt, aber nach Auseinandersetzungen mit den Schauspielern verließ er 1799 Wien. Unter Direktor Joseph Schreyvogel wurde Deutsch statt Französisch und Italienisch als neue Bühnensprache eingeführt. + +Am 12. Oktober 1888 fand die letzte Vorstellung im alten Haus statt. Das Burgtheaterensemble übersiedelte in die neue Spielstätte am Ring. Das alte Burgtheater musste der Komplettierung des Michaelertrakts der Hofburg weichen. Die Pläne dazu hatte Joseph Emanuel Fischer von Erlach bereits knapp 200 Jahre vor dem Abriss des alten Burgtheaters gezeichnet. Eine 1817 errichtete, originalgetreue (aber verkleinerte) Kopie des Theatersaales befindet sich im rumänischen Oravita.[3] + +Das neue Gebäude am Ring[Bearbeiten] + +K.k. Hofburgtheater um 1900 + +Das bereits 1865 von Semper geplante, nicht realisierte Münchner Festspielhaus an der Isar + +„Das Theater von Taormina“ von Gustav Klimt, Deckengemälde in der Erzherzogsstiege + +Das Eingangsfoyer heute +Das „neue“ k.k. Hofburgtheater (wie die Aufschrift bis heute lautet) am Ring gegenüber dem Rathaus, am 14. Oktober 1888 mit Grillparzers Esther und Schillers Wallensteins Lager eröffnet, wurde im neubarocken Stil von Gottfried Semper (Grundriss) und Karl Freiherr von Hasenauer (Fassade) entworfen, die bereits das Kaiserforum in Wien gemeinsam geplant hatten. Die Bauarbeiten begannen am 16. Dezember 1874 und zogen sich 14 Jahre hin, in denen sich das Architektenduo zerstritt. Bereits 1876 zog sich Semper auf Grund gesundheitlicher Probleme nach Rom zurück und ließ Hasenauer seine Ideen alleine realisieren, der sich im Streit der Architekten vor allem für ein prachtvoll ausgestaltetes Logentheater eingesetzt hatte. + +Indes schuf der bekannte Wiener Maler Gustav Klimt gemeinsam mit seinem Bruder Ernst Klimt und mit Franz Matsch 1886–1888 die Deckengemälde in den beiden Stiegenhäusern des neuen Theaters. Die drei übernahmen diese Aufgabe nach ähnlichen Auftragsarbeiten in den Stadttheatern von Fiume und Karlsbad sowie im Bukarester Nationaltheater. In der Feststiege auf der dem Café Landtmann zugewandten Seite des Burgtheaters (Erzherzogstiege) bildete Gustav Klimt die Künstler des antiken Theaters in Taormina auf Sizilien, im Stiegenhaus auf der „Volksgarten“-Seite (Kaiserstiege, weil sie dem Kaiser vorbehalten war) das Londoner Globe Theatre und die Schlussszene aus William Shakespeares „Romeo und Julia“ nach. Über dem Eingang zum Zuschauerraum ist Der Eingebildete Kranke Molières zu entdecken. Im Hintergrund verewigte sich der Maler in Gesellschaft seiner beiden Kollegen. Kaiser Franz Joseph I. gefielen die Deckengemälde so sehr, dass er den Mitgliedern der Künstlerkompanie von Klimt das Goldene Verdienstkreuz verlieh. + +Das neue Gebäude ähnelt äußerlich der Dresdner Semperoper, mehr noch aber, aufgrund der beiden für Theaterbauten absolut untypischen Querflügel mit den Prunkstiegen, Sempers Münchner Projekt aus den Jahren 1865/1866 für ein Richard-Wagner-Festspielhaus über der Isar. Über dem Mitteltrakt befindet sich eine Loggia, die von zwei Seitenflügeln eingerahmt und aus einem Bühnenhaus mit Giebeldach und einem Zuschauerhaus mit Zeltdach geteilt wird. Über dem Mittelhaus schmückt eine Statue von Apollon die Fassade, der zwischen den Musen für Drama und Tragödie thront. Über den Haupteingängen befinden sich Friese mit Bacchus und Ariadne. An der Außenfassade rundum sind Porträtbüsten der Dichter Calderon, Shakespeare, Molière, Schiller, Goethe, Lessing, Halm, Grillparzer und Hebbel zu sehen. Die Masken, die ebenfalls hier zu sehen sind, weisen auf das antike Theater hin, außerdem schmücken allegorische Darstellungen die Seitentrakte: Liebe, Hass, Demut, Herrschsucht, Egoismus und Heroismus. Obwohl das Theater seit 1919 den Namen Burgtheater trägt, ist die alte Aufschrift K.K. Hofburgtheater über dem Haupteingang immer noch vorhanden. Einige Bilder der alten Porträtgalerie wurden im neuen Gebäude aufgehängt und sind heute noch zu sehen – allerdings waren diese Bilder ursprünglich kleiner, man musste sie „verlängern“, damit sie im hohen Raum besser wirken. Die Stellen dieser „Ergänzungen“ sind als feine Linien auf der Leinwand sichtbar. + +Das Burgtheater wurde zunächst auf Grund seines prachtvollen Aussehens und der technischen Neuerungen wie elektrischer Beleuchtung von den Wienern gut aufgenommen, doch bald wurde Kritik an der schlechten Akustik laut. 1897 erfolgte schließlich ein Umbau des Zuschauerraums, um die Akustikprobleme zu mindern. Das neue Theater wurde zu einem wichtigen Treffpunkt des Gesellschaftslebens und zählte schon bald zu den „Heiligtümern“ der Wiener. Im November 1918 ging die Aufsicht über das Theater vom Obersthofmeister des Kaisers auf den neuen Staat Deutschösterreich über. + +1922/1923 wurde das Akademietheater als Kammerspielbühne des Burgtheaters eröffnet. Am 8. Mai 1925 ging das Burgtheater in die österreichische Kriminalchronik ein, als hier Mentscha Karnitschewa ein Revolverattentat auf Todor Panitza verübte. + +Das Burgtheater in der Zeit des Nationalsozialismus[Bearbeiten] +Die nationalsozialistischen Ideen hinterließen auch Spuren in der Geschichte des Burgtheaters. 1939 erschien im Adolf Luser Verlag das stark antisemitisch geprägte Buch des Theaterwissenschaftlers Heinz Kindermann „Das Burgtheater. Erbe und Sendung eines Nationaltheaters“, in dem er unter anderem den „jüdischen Einfluss“ auf das Burgtheater analysierte.[4] Am 14. Oktober 1938 wurde zum 50-jährigen Eröffnungsjubiläum des Burgtheaters eine Don-Carlos-Inszenierung von Karl-Heinz Stroux gezeigt, die die Ideologie Hitlers bediente. Die Rolle des Marquis Posa spielte derselbe Ewald Balser, der ein Jahr zuvor in einer anderen Don-Carlos-Inszenierung (von Heinz Hilpert) am Deutschen Theater in derselben Rolle mit dem Satz Richtung Joseph Goebbels’ Loge wetterte: „Geben Sie Gedankenfreiheit!“. Der Schauspieler und Regisseur Lothar Müthel, der zwischen 1939 und 1945 Direktor des Burgtheaters war, inszenierte 1943 den Kaufmann von Venedig, in dem Werner Krauß den Juden Shylock eindeutig antisemitisch darstellte. Derselbe Regisseur inszenierte nach dem Krieg Lessings Parabel Nathan der Weise. Adolf Hitler selbst besuchte während des NS-Regimes das Burgtheater nur einmal (1938), später weigerte er sich aus panischer Angst vor einem Attentat. + +Für die Schauspieler und Theatermitarbeiter, die nach dem Reichsbürgergesetz von 1935 als „jüdisch“ eingestuft wurden, wurde rasch Auftrittsverbot verhängt, sie wurden innerhalb weniger Tage beurlaubt, entlassen oder verhaftet. Das Burgtheater-Ensemble leistete zwischen 1938 und 1945 keinen nennenswerten Widerstand gegen die NS-Ideologie, der Spielplan wurde stark zensiert, nur wenige schlossen sich aktiv dem Widerstand an, so Judith Holzmeister (damals auch am Volkstheater engagiert) oder der Schauspieler Fritz Lehmann. Den jüdischen Ensemblemitgliedern wurde zwar zur Emigration verholfen, dennoch wurde ein Schauspieler, Fritz Strassny, in ein Konzentrationslager gebracht und dort ermordet.[5] + +Das Burgtheater zu Kriegsende und nach dem Zweiten Weltkrieg[Bearbeiten] +Im Sommer 1944 musste auch das Burgtheater wegen der angeordneten allgemeinen Theatersperre geschlossen werden. Ab 1. April 1945, als sich die Rote Armee Wien näherte, lagerte eine militärische Einheit im Haus, ein Teil wurde als Waffenlager benutzt. Bei einem Bombenangriff wurde das Haus am Ring beschädigt und brannte am 12. April 1945 völlig aus. Zuschauerraum und Bühne wurden unbrauchbar, nur die Stahlkonstruktion blieb erhalten. Die Deckengemälde und Teile des Foyers waren beinahe unbeschädigt. + +Die sowjetische Besatzungsmacht erwartete vom Wiener Kulturstadtrat Viktor Matejka, Wiens Kulturleben so rasch wie möglich wieder in Gang zu bringen. Der Stadtrat berief daher für den 23. April (eine Staatsregierung bestand noch nicht) eine Versammlung aller Wiener Kulturschaffenden ins Rathaus ein. Resultat der Besprechungen war, dass Ende April 1945 acht Kinos und vier Theater den Betrieb wieder aufnahmen, darunter das Burgtheater.[6] Das Haus übernahm das Etablissement Ronacher, das von vielen Burgschauspielern als „Exil“ verstanden wurde, als Ausweichquartier (und blieb dort bis 1955). Diesen Spielort wählte der neu ernannte Direktor Raoul Aslan aus, der sich besonders engagiert einsetzte. + +Die erste Vorstellung nach dem Zweiten Weltkrieg war am 30. April 1945 Sappho von Franz Grillparzer in der Inszenierung von Adolf Rott aus dem Jahre 1943 mit Maria Eis in der Titelrolle. Auch andere Produktionen aus der NS-Zeit wurden wieder aufgenommen. Mit Paul Hörbiger, als NS-Häftling wenige Tage vorher noch in Lebensgefahr, wurde Nestroys Stück Das Mädl aus der Vorstadt gezeigt. Das Akademietheater konnte bespielt werden (die erste Aufführung war am 19. April 1945 Hedda Gabler, eine Inszenierung von Rott aus dem Jahre 1941) und auch im Redoutensaal in der Hofburg fanden Vorstellungen statt. Aslan ließ das Ronacher im Sommer umbauen, weil die Bühne für klassische Aufführungen zu klein war. Am 25. September 1945 konnte auf der vergrößerten Bühne Schillers Jungfrau von Orleans gespielt werden. + +Die ersten Neuinszenierungen sind mit dem Namen von Lothar Müthel verbunden: Jedermann und Nathan der Weise, in beiden spielte Raoul Aslan die Hauptrolle. Die Inszenierung des Kaufmanns von Venedig von Müthel zu NS-Zeiten schien in Vergessenheit geraten zu sein. + + +Das Burgtheater auf der Rückseite der 50-Schilling-Banknote (1970) +Große Freude bereitete dem Publikum die Rückkehr der 1938 aus dem Ensemble vertriebenen Else Wohlgemuth auf die Bühne. Sie trat nach sieben Jahren Exil im Dezember 1945 in Klara Biharys Die andere Mutter im Akademietheater auf. 1951 öffnete das Burgtheater das erste Mal seine Pforten, allerdings nur den linken Seitenflügel, wo die Feierlichkeiten zum 175-jährigen Bestehen des Theaters stattfanden. + +1948 wurde für den Wiederaufbau ein Wettbewerb ausgeschrieben: Josef Gielen, der damals Direktor war, tendierte zuerst dazu, den ex aequo erstgereihten Entwurf von Otto Niedermoser zu unterstützen, nach dem das Haus in ein modernes Rangtheater hätte umgebaut werden sollen. Schließlich stimmte er dann aber doch für das Projekt von Michel Engelhart, dessen Plan konservativer, aber auch kostengünstiger war. Der Charakter des Logentheaters wurde weitgehend berücksichtigt und beibehalten, die zentrale Hofloge wurde allerdings durch zwei Ränge ersetzt, und durch eine neue, schräge Deckenkonstruktion im Zuschauerraum wurde die Akustik, die Schwäche des Hause, deutlich verbessert. + +Am 14. Oktober 1955 kam es unter dem neuen Direktor Adolf Rott zur Wiedereröffnung des restaurierten Hauses am Ring. Aus diesem Anlass wurde Mozarts Eine kleine Nachtmusik gespielt. Am 15. und am 16. Oktober folgte die erste Aufführung (aus Platzgründen als Doppelpremiere) im wiederhergestellten Theater: König Ottokars Glück und Ende von Franz Grillparzer, inszeniert von Adolf Rott. Wenige Monate nach Unterzeichnung des Österreichischen Staatsvertrags war die Wahl dieses Stückes, das den Beginn der Habsburgerherrschaft in Österreich thematisiert und Ottokar von Hornecks Lobspruch auf Österreich (… es ist ein gutes Land, / Wohl wert, dass sich ein Fürst sein unterwinde! / Wo habt Ihr dessengleichen schon gesehn? …) enthält, äußerst symbolträchtig. Unter Rott und seinen Nachfolgern Ernst Haeusserman und Gerhard Klingenberg wurden der klassische Burgtheaterstil und das Burgtheaterdeutsch für die deutschen Bühnen endgültig richtungweisend. + +In den 1950er und 1960er Jahren beteiligte sich das Burgtheater (mit anderen namhaften Wiener Theatern) am sogenannten Brecht-Boykott. + +Das Burgtheater heute[Bearbeiten] + +Die Kaiserstiege im südlichen Seitenflügel des Burgtheaters + +Der heutige Zuschauerraum mit Blick auf die Festloge im 1. Rang rechts +Gerhard Klingenberg internationalisierte das Burgtheater, er lud bedeutende Regisseure wie Dieter Dorn, Peter Hall, Luca Ronconi, Giorgio Strehler, Roberto Guicciardini und Otomar Krejča ein. Klingenberg ermöglichte auch die Burg-Debüts von Claus Peymann und Thomas Bernhard (1974 Uraufführung von Die Jagdgesellschaft). Bernhard war als Nachfolger Klingenbergs im Gespräch, schließlich wurde aber Achim Benning ernannt, worauf der Schriftsteller mit dem Text „Die theatralische Bruchbude auf dem Ring (Wie ich Burgtheaterdirektor werden sollte)“ antwortete. + +Benning, der erste Ensemblevertreter des Burgtheaters, der zum Direktor ernannt wurde, setzte Klingenbergs Weg der Europäisierung mit anderen Mitteln fort, brachte Regisseure wie Adolf Dresen, Manfred Wekwerth oder Thomas Langhoff nach Wien, blickte mit Aufführungen von Stücken Václav Havels in den damals politisch abgetrennten Osten und nahm stärker Rücksicht auf den Publikumsgeschmack. + +Direktion Claus Peymann 1986–1999[Bearbeiten] +Unter dem von Kurzzeit-Unterrichtsminister Helmut Zilk nach Wien geholten Claus Peymann, Direktor 1986 bis 1999, kam es zu weiterer Modernisierung des Spielplans und der Inszenierungsstile. Außerdem war Peymann nie um kritische Wortmeldungen in der Öffentlichkeit verlegen; eine bis dahin für Burgtheaterdirektoren unübliche Haltung. Er und sein Programm stießen daher bei Teilen des Publikums auf Ablehnung. Den größten Wiener Theaterskandal seit 1945 gab es 1988 um die von konservativen Politikern und Eiferern heftig bekämpfte Uraufführung von Thomas Bernhards Drama Heldenplatz. Das Stück setzt sich mit der Vergangenheitsbewältigung Österreichs auseinander und beleuchtet die Gegenwart – mit Attacken auf die damals regierende SPÖ – kritisch. Gemeinsam mit Claus Peymann stellte sich Bernhard nach der Premiere auf der Bühne Applaus und Buhrufen. + +Bernhard, seinem Heimatland in Hassliebe verbunden, verbot vor seinem Tod 1989 die Aufführung seiner Stücke in Österreich testamentarisch. Peymann, der Bernhard in schwieriger Freundschaft verbunden war (siehe Bernhards Stück Claus Peymann kauft sich eine Hose und geht mit mir essen), befürchtete Schaden für das Werk des Autors, sollten seine Stücke ausgerechnet in seiner Heimat nicht gezeigt werden. Zunächst war es durch eine Erlaubnis des Testamentsvollstreckers Peter Fabjan – Bernhards Halbbruder – immerhin möglich, die bereits im Spielplan des Burgtheaters befindlichen Produktionen weiterzuspielen. Kurz vor Bernhards zehntem Todestag kam es schließlich zur Neuinszenierung des Bernhard-Stückes Vor dem Ruhestand durch den Uraufführungsregisseur Peymann. Die Stücke von Bernhard stehen seither weiter auf dem Spielplan des Burgtheaters und werden regelmäßig neu herausgebracht. + +1993 wurde die Probebühne des Burgtheaters im Arsenal eröffnet (Architekt: Gustav Peichl). Seit 1999 hat das Burgtheater die Betriebsform einer Ges.m.b.H. + +Direktion Klaus Bachler 1999–2009[Bearbeiten] +Auf Peymann folgte 1999 Klaus Bachler als Direktor. Er ist ausgebildeter Schauspieler, war aber zumeist als Kulturmanager (Intendant der Wiener Festwochen) tätig. Bachler rückte das Theater als kulturelles Ereignis in den Vordergrund und engagierte dazu Regisseure wie Luc Bondy, Andrea Breth, Nicolas Brieger, Peter Zadek und Martin Kušej. Ihm wird vorgeworfen, dass er die Burg „nicht gestaltet, sondern nur verwaltet“ hätte und wahllos große Namen im internationalen Theaterbetrieb zu Inszenierungen eingeladen habe. „Am Ende der Ära Bachler war die Burg nicht Fisch, nicht Fleisch“.[7] + +Zu den ungewöhnlichen „Events“ der Direktion Bachler zählten das Orgien-Mysterien-Theater von Hermann Nitsch mit der Performance 122. Aktion (2005), die Aufzeichnung des MTV-Unplugged-Konzerts mit den Toten Hosen für den Musiksender MTV (2005; unter dem Titel Nur zu Besuch erhältlich), John Irvings Lesung im Burgtheater aus seinem Buch Bis ich dich finde (2006), Die 431. animatographische Expedition von Christoph Schlingensief und eine große Veranstaltung von ihm unter dem Titel Area 7 – Sadochrist Matthäus – Eine Expedition von Christoph Schlingensief (2006). Daniel Hoevels schnitt sich in Schillers Maria Stuart versehentlich die Kehle auf (Dezember 2008). Ambulante Versorgung reichte aus.[8] + +Im Oktober 2005 feierte das Burgtheater den 50. Jahrestag seiner Wiedereröffnung mit einem Galaabend und mit der Aufführung von Grillparzers König Ottokars Glück und Ende in der Inszenierung von Martin Kušej, die im August 2005 bei den Salzburger Festspielen mit großem Erfolg aufgeführt worden war. Michael Maertens (in der Rolle von Rudolf von Habsburg) erhielt den Nestroy-Theaterpreis als bester Schauspieler für seine Rolle in diesem Stück. Hauptdarsteller Tobias Moretti wurde 2006 für diese Rolle mit dem Gertrud-Eysoldt-Ring ausgezeichnet. Weiters gab es am 16. Oktober 2005 einen Tag der offenen Tür, an dem der 82-minütige Film „burg / privat. 82 miniaturen“ von Sepp Dreissinger zum ersten Mal gezeigt wurde. Der Film enthält einminütige filmische „Standportraits“ von Burgschauspielern und Gastschauspielern, die, ohne ein Wort zu sagen, versuchen, sich mit einem möglichst natürlichen Gesichtsausdruck zu präsentieren. Klaus Dermutz schrieb ein Werk über die Geschichte des Burgtheaters. Als Motto dieser Spielzeit diente ein Zitat aus Lessings Minna von Barnhelm: „Es ist so traurig, sich allein zu freuen.“ + +Auch des Mozart-Jahres 2006 wurde im Burgtheater gedacht. Da Mozarts Singspiel Die Entführung aus dem Serail 1782 im Hof-Burgtheater uraufgeführt worden war, kam in Zusammenarbeit mit der Wiener Staatsoper zu den Wiener Festwochen im Mai 2006 eine Neuinszenierung (Regie: Karin Beier) dieser Oper auf die Bühne. + +Im April 2014 wollte ein von der Zeitschrift NEWS in Auftrag gegebenes Attest des unabhängigen Juristen Karl Newole den Vorgang der Untreue nicht ausschließen, weil Bachler 2009 in Wien volles Gehalt bezogen habe, obwohl er schon als Intendant der Münchner Oper tätig war. + +Direktion Matthias Hartmann 2009–2014[Bearbeiten] + +Kleists Prinz von Homburg, Kopro­duktion mit den Salzburger Festspielen, Peter Simonischek und August Diehl, inszeniert von Andrea Breth, 2012 +Von September 2009 bis zum 11. März 2014 war Matthias Hartmann künstlerischer Geschäftsführer des Burgtheaters. Der aus Osnabrück stammende Regisseur leitete zuvor die Schauspielhäuser Bochum und Zürich. Mit ihm kamen Regisseure wie Alvis Hermanis, Roland Schimmelpfennig, David Bösch, Stefan Bachmann, Stefan Pucher, Michael Thalheimer und Schauspieler wie Dörte Lyssewski, Katharina Lorenz, Sarah Viktoria Frick, Mavie Hörbiger, Lucas Gregorowicz, August Diehl und Martin Wuttke fest an die Burg. Selber inszeniert Matthias Hartmann rund drei Premieren pro Saison, etwa einmal im Jahr inszeniert er an den großen Opernhäusern. Für mehr Internationalität und „cross-over“ konnte er den belgischen Künstler Jan Lauwers und seine Needcompany als „Artists in Residence“ für die Burg gewinnen, die New Yorker Gruppe Nature Theater of Oklahoma zeigen ihr großes Episodendrama Live and Times als jährliche Fortsetzung. Für das neue Erscheinungsbild – das Burgtheater präsentiert sich ohne festes Logo mit Wortspielen rund um die BURG – wurde das Burgtheater 2011 mit der Kulturmarke des Jahres ausgezeichnet.[9] + +Hartmann konnte die Auslastung des Theaters gegenüber der Ära Bachler um 15 Prozent steigern (Vergleich der Spielzeiten 2008/09 und 2011/12). In den nur viereinhalb Jahren seiner Amtszeit wurde das Burgtheater siebenmal zum Berliner Theatertreffen eingeladen. Vorgänger Klaus Bachler brachte es in 10 Jahren auf neun Einladungen. Hartmann wurde jedoch auch vom Schriftsteller Peter Truschner vorgeworfen, dass er nach der Ära Bachler „in seiner Selbstbesoffenheit und der damit einhergehenden Selbstbereicherung dem Burgtheater erst recht nicht gedient“ habe.[7] + +Hartmann wurde im Auftrag von Kulturminister Josef Ostermayer am 11. März 2014 von der Bundestheater-Holding fristlos entlassen, weil vom Minister eingeholte Rechtsgutachten die grobe Missachtung von Geschäftsführerpflichten durch Hartmann festgestellt haben.[10][11] Der Abberufung Hartmanns war am 18. November 2013 die fristlose Entlassung der früheren kaufmännischen Leiterin des Hauses, Silvia Stantejsky, vorausgegangen.[12] Im Zusammenhang mit diesen Vorgängen wurde auch heftige Kritik am Aufsichtsrat des Burgtheaters und an Holding-Geschäftsführer Georg Springer geübt. + +Finanzskandal 2013/2014[Bearbeiten] +Das Burgtheater kam im Winter 2013 / 2014 in die Medien, als Unregelmäßigkeiten in der Buchführung zur Entlassung der Stellvertreterin des künstlerischen Direktors, Silvia Stantejsky führten. Wirtschaftsprüfer stellten in einer Gebarungsprüfung der von Stantejsky als kaufmännische Geschäftsführerin verantworteten Geschäftsjahre Ungereimtheiten fest, die nicht geklärt werden können.[13] Finanzielle Probleme des Burgtheaters kamen zuvor schon an die Öffentlichkeit: So weist beispielsweise der Geschäftsbericht zur Spielsaison 2011/2012 einen nicht liquiditätswirksamen Jahresfehlbetrag von 3,705 Millionen Euro und als Konsequenz eine Kapitalherabsetzung in gleicher Höhe aus.[14] + +Die fristlose Entlassung Stantejskys fand am 18. November 2013 statt.[15] Am 3. Jänner 2014 berichtet das Magazin News erstmals von der Entlassung.[16] Am 9. Jänner erhielt das Wirtschaftsprüfungsunternehmen KPMG den Auftrag zu einer forensischen Untersuchung der gegen Stantejsky vorliegenden Verdachtsmomente. In einem Interview der ZiB 2 vom 22. Jänner erhob Georg Springer, der Geschäftsführer der Bundestheater Holding, schwere Vorwürfe gegen Stantejsky: Diese habe eine sehr intelligente Schattenorganisation aufgebaut und dolose Handlungen gesetzt. Sechs Tage später bestritt Stantejsky in einem Interview mit dem Radiosender Ö1 sämtliche Vorwürfe energisch: Sowohl Dr. Springer als auch der Aufsichtsrat wird von sämtlichen buchhalterischen Entscheidungen informiert. Parallel kann gar nichts geschehen. + +Am 10. Februar 2014 veröffentlichte KPMG einen Zwischenbericht: Dieser ortete deutliche Indizien für gefälschte Belege und die Vorspiegelung falscher Tatsachen durch Silvia Stantejsky. Laut Aufsichtsrat des Burgtheaters sei daher für das Jahr 2012/13 mit einem Bilanzverlust von voraussichtlich 8,3 Millionen Euro zu rechnen. Dazu könnten 5 Millionen Euro Steuernachzahlungen kommen. + +Am 24. Februar brachte die Nationalratsfraktion NEOS eine 72 Fragen umfassende dringliche Anfrage zur Causa Burgtheater ein.[17] Zugleich kündigte der (damals noch designierte) Kulturminister Josef Ostermayer an, den österreichischen Rechnungshof um eine Prüfung der Finanzgebarung des Burgtheaters zu ersuchen.[15] + +Am 27. Februar 2014 wurde bekannt, dass eine anonyme Anzeige gegen Silvia Stantejsky bei der Korruptions-Staatswanwaltschaft eingegangen sei.[18] Am selben Tag legte KPMG den forensischen Untersuchungsbericht vor. Darin heißt es, die kaufmännische Direktion von Stantejsky sei sehr zentralisiert gesteuert und wie eine Containerorganisation geführt worden. Weiters habe sich der Verdacht auf Urkunden-, Beweismittel- und Bilanzfälschung, Geldwäsche sowie Untreue ergeben.[19] + +In einem Presse-Interview vom Vortag übte Martin Wagner, Senior-Partner der KPMG, Kritik an Hartmann und Springer: An der Entwicklung der Bankschulden konnte man leicht erkennen, dass das Haus verlustträchtig ist. Wenn man mehr ausgibt, als man hat, dann steigen die Schulden. Wenn dann trotzdem ein ausgeglichenes Ergebnis vorliegt, sagt einem der Hausverstand, dass da etwas nicht zusammenpasst.[20] + +Die finanziellen Verluste wurden im Prüfbericht auf über 8 Millionen Euro beziffert, dazu kommen laut Medienberichten noch rund 5 Millionen Euro an Steuernachzahlungen.[21] Die Verluste seien verschleiert worden, indem Einnahmen fälschlich ins Vorjahr und Ausgaben ins Folgejahr gebucht wurden. Die dazu erstellten Belege hätten die Unterschrift Hartmanns benötigt, diese fehlt aber auf den Buchungsbelegen. Daher wurde seit Anfang März 2014 ein von ihm zu verantwortender „Systemfehler“ diskutiert.[22] Am 10. März versuchte Hartmann noch sein Amt ruhend zu stellen[23], er wurde aber am Folgetag von Kulturminister Josef Ostermayer entlassen.[24][25] + +Hartmann selbst machte geltend, das Haus wäre nach 14 Jahren ohne Inflationsabgeltung bei massiv gestiegenen Personalkosten nicht mehr dem Gesetzesauftrag entsprechend betreibbar gewesen. Er habe auf diesen Umstand mehrfach hingewiesen und auch das „System Stantejsky“ frühzeitig beim Eigentümer, der Bundestheater-Holding, hinterfragt. Selbst die Beiziehung des Berliner Theaterexperten Peter F. Raddatz im Jahr 2011 habe die Holding allerdings nicht zum Handeln bewogen. + +Hartmann hat gegen die Entlassung gerichtliche Schritte ergriffen. Über seine Anwälte erklärte er den Vorgang für rechtswidrig und unwirksam und klagt knapp zwei Millionen Euro ein. Diese Summe errechnet sich aus den Jahresgehältern für seine Direktorenfunktion bis zum ursprünglichen Vertragsende im Sommer 2019 und aus Honoraren für seine Tätigkeit als Regisseur. + +Direktion Karin Bergmann 2014 bis voraussichtlich 2019[Bearbeiten] +→ Hauptartikel: Burgtheaterbesetzungen ab 2014 + +Die Schutzbefohlenen + +Das Reich der Tiere, 2015 + +Die letzten Tage der Menschheit, 2014 +Am 19. März 2014 wurde Karin Bergmann von Josef Ostermayer zur interimistischen Direktorin des Burgtheaters bestellt. Sie sollte dieses Amt bis zum 30. August 2016 innehaben.[26] Im April 2014 wurde bekannt, dass der damalige Burgtheaterdirektor Klaus Bachler Frau Bergmann 2009 insgesamt 32.400 Euro als steuerfreie „Schenkung“ überwiesen hat. Bergmann wäre der behördlichen Meldepflicht für Schenkungen aber nicht nachgekommen. Bachler war 2008/09 bereits Intendant der Münchner Oper, bezog aber auch in Wien volles Gehalt, während seine Vizedirektorin Bergmann die Geschäfte führte. Deshalb wurde angezweifelt, dass es sich tatsächlich um eine Schenkung gehandelt habe. Ein von der Zeitschrift NEWS in Auftrag gegebenes Attest des unabhängigen Juristen Karl Newole von einer „verunglückten Hilfskonstruktion“. Die Schenkung wäre „entweder eine direkte steuerpflichtige Honorzahlung oder eine Art indirekte Gehaltserhöhung“ gewesen. Die Zeitung Die Presse meldete außerdem, dass Bergmanns Ehemann, dem Architekten Luigi Blau, in der Ära Bachler ohne Ausschreibung sieben Aufträge des Burgtheaters zugegangen sind. Bergmann habe diesen Vorgang allerdings nicht goutiert. + +Am 24. Oktober 2014 wurde Karin Bergmann definitiv zur Direktorin des Burgtheaters bis zum Jahr 2019 bestellt. Es hatte einen Findungsprozess mit insgesamt 29 Interessenten gegeben, die sich entweder beworben hätten oder angesprochen worden seien. Mit den zwei Kandidaten des Vorschlages der Findungskommission hat es laut Kulturminister Josef Ostermayer ausführliche Gespräche gegeben. Der Aufsichtsrat hat dann einstimmig den Vorschlag des Ministers gutgeheißen. Für Bergmann habe nicht nur der Vorschlag der Findungskommission, sondern auch „ihre bisherige Performance“ bei der interimistischen Leitung gesprochen, so Ostermayer bei der Präsentation der Entscheidung vor der Presse. + +Hinter den Kulissen[Bearbeiten] +Bühnentechnik und andere technische Besonderheiten[Bearbeiten] + +Umbauarbeiten auf der Bühne des Burgtheaters +Der Zuschauerraum bietet etwa 1.340 Zuschauern Platz (1.175 Sitzplätze) und ist damit einer der größten unter Europas Schauspielhäusern. Das Bühnen-Portal ist 12 m breit und am höchsten Punkt 9 m hoch. Die Schnürböden und Beleuchtungsbrücken befinden sich in 28 m Höhe. Die Bühnenfläche beträgt rund 780 m², bei einer Breite von 31 Metern und einer Tiefe von etwa 25 Metern – sie kann allerdings durch eine Erweiterung im Cercle-Bereich erweitert werden.[27] Die Bühne selbst befindet sich im 1. Stock des Theatergebäudes, für die Schauspieler gibt es auf beiden Seiten der Bühne je zwei Eingänge. Im Hinterbühnenbereich existiert ein großer Aufzug, der 20 Meter breit und 1,5 Meter tief ist und somit zur Beförderung von Dekorationen geeignet ist, die zwar sehr breit und bis zu 3,5 Meter hoch, aber nur knapp 1,25 Meter tief sein dürfen. Größere Kulissenteile können nur gekippt transportiert werden. + +Die Bühne wurde 1954 von der österreichischen Firma Waagner Biro, die auch bei anderen Bühnen- und Opernhäusern Erfahrung besitzt, neu errichtet. Die Hauptbühne ist mit einer Drehzylinderbühne ausgestattet, die einen Durchmesser von 21 m und vier Versenkungen hat, die bis 8,8 m abgefahren werden können. Sie wurde nach den Plänen von Sepp Nordegg errichtet und ist insgesamt 5 Stockwerke tief, so können die Bühnenbilder im Paternoster-Prinzip getauscht werden. Die im Jahr 1994 begonnene Bühnenrenovierung wurde 2004 beendet, dabei wurde unter anderem die alte Steuerung durch eine Computersteuerung ersetzt. Die Drehzylinderbühne hat zwei Bühnenwagen und vier Versenkungen, eine Drehbühne mit 21 Meter Durchmesser und sechs Orchesterversenkungen, die für 70 Musiker Platz bieten. + +Der Eiserne Vorhang des Burgtheaters wiegt 16,8 Tonnen und kann im Notfall – zum Beispiel bei einem Brand – den Bühnenraum vom Zuschauerraum innerhalb von 28 Sekunden trennen und hält die Flammen mindestens 20 Minuten auf.[28] Nach dem Großbrand des Ringtheaters wurden alle Wiener Theater verpflichtet, die Bühnen mit einem Eisernen Vorhang zu versehen. Der alte wurde allerdings nach dem Zweiten Weltkrieg durch den heutigen ausgetauscht. Das Burgtheater hat eine hauseigene Betriebsfeuerwehr, die unter anderem prüfen muss, ob im Fall einer Alarmmeldung durch einen der besonders sensiblen Rauchmelder möglicherweise ein kontrolliertes Feuer auf der Bühne die Ursache ist, aber natürlich auch im Ernstfall die ersten Löscharbeiten durchführen muss. + + +Plan des Belüftungssystems (Ignaz Gridl) + +Die „Schwammerl“ genannte Luftansaughütte im Volksgarten + +Das Innenleben der Luftansaughütte +Architektonisch einzigartig und patentiert ist die riesige Luftschleuse, das Belüftungssystem des Theaters, das sich unter dem runden Dach der Luftansaughütte, von den Wienern einfach Schwammerl genannt, auf der Seite des Volksgartens verbirgt und nach den Plänen des Architektenbüros von Ignaz Gridl konstruiert wurde. Die Luft wird durch Filter geblasen, gereinigt und temperiert. Die verbrauchte Luft wird aus dem Zuschauerraum durch das Messinggitter des Kristalllusterkranzes im Zentrum der Saaldecke aus dem Raum ins Freie abgezogen. Den Sog dafür erzeugt der „Blasengel“, eine grüne Engelsfigur mit einem Blasinstrument, die als Wetterfahne auf der Kuppel steht. Diesen Teil des Belüftungssystems kann man am besten im Dachboden („Lusterboden“) und auf dem Kuppeldach des Theaters betrachten. Früher standen auf dem steilen Dach des Burgtheaters sogar Duschen und Toiletten (sie wurden gleich beim Wiederaufbau des Theaters nach dem Zweiten Weltkrieg errichtet), damit die Schauspieler in den Pausen zwischen den Proben ein Sonnenbad nehmen können. Seit 1977 ist dies allerdings verboten, die Anlagen wurden wieder abgetragen. Auf dem Dach ist eine Wetterkamera installiert, die bei der Sendung Wetterpanorama Österreich im Fernsehen einen Blick auf die Ringstraße ermöglicht. + +Die Souffleure am Burgtheater arbeiten mit Funktechnik, es gibt keinen Souffleurkasten mehr. + +Führungen durchs Haus finden jeden Tag um 15 Uhr auf Deutsch und an Freitagen, Samstagen, Sonntagen und Feiertagen auch auf Englisch statt. Während der Monate Juli und August finden an allen Wochentagen deutsche und englische Führungen statt. Außerdem finden auch an Freitagen, Samstagen, Sonntagen und Feiertagen jeweils um 14.00 Klimt-Führungen durch das Burgtheater statt. + +Kostüme, Requisiten[Bearbeiten] + +Eine Perücke aus der Burgtheater-Werkstatt +Die Kostümwerkstätten sind im 1. Bezirk, im Hanuschhof, untergebracht, Requisiten und Bühnenbildwerkstätten des Burgtheaters befinden sich im Arsenal. Sie versorgen nicht nur Burgproduktionen, sondern sie arbeiten auch auf Bestellung für andere österreichische und internationale Bühnen. Die Werkstätten arbeiten in Form einer GmbH (Art for Art – Theaterservice GmbH). Außerdem ist es Privatpersonen möglich, Kostüme aus dem Fundus auszuleihen. Die Kostüme und die Requisiten werden sorgfältig ausgesucht und aufwändig hergestellt, es werden meist nur Perücken aus echten Haaren verwendet, deren Herstellung oft zwei bis drei Wochen dauern kann. Ein Großlager für gerade nicht verwendete Kostüme befindet sich in der Montleartstraße im 14. Bezirk. + +Weitere Spielstätten und Probebühnen des Burgtheaters[Bearbeiten] + +Der Lusterboden des Hauses + +Anatomischer Saal der Akademie der Bildenden Künste + +Die Probebühne in den Werkstätten im Arsenal +Das Akademietheater, in den Jahren 1911 bis 1913 von den Architekten Fellner und Helmer und Ludwig Baumann erbaut, ist seit 1922 die zweite Spielstätte des Burgtheaters. Es wurde seither umgebaut und bühnentechnisch erneuert. +Das Kasino am Schwarzenbergplatz gilt als Spielstätte für Gegenwartsstücke und Spezialprojekte. Es wurde unter Direktor Benning am 26. April 1981 als 3. Raum am Schwarzenbergplatz eröffnet und wird seither mit Unterbrechungen (siehe Lusterboden) bespielt. Der gegenwärtige Name stammt aus der Direktion Peymann, die den Raum zunächst nur als Probebühne nutzte.[29] +Das Vestibül ist die Studiobühne des Burgtheaters und befindet sich unter der dem Café Landtmann zugewandten Feststiege. Das Vestibül wurde in den 1990er Jahren für Aufführungen hergerichtet. +Der Lusterboden ist eine im Dachgeschoss des Burgtheaters in einer Höhe von 43 Metern befindliche Probebühne. Diesen Raum im Dachboden gibt es seit 1955, er wird unter anderem als Requisitenlager verwendet. Ab dem 16. September 1979 wurde er auch immer wieder für Aufführungen herangezogen (zuerst als 3. Raum – Lusterboden, später nur Lusterboden), dann durch den Raum am Schwarzenbergplatz ersetzt. Als dieser wieder für Proben verwendet wurde, griff man unter Peymann erneut auf den Lusterboden als Aufführungsstätte zurück, von 1986 bis 1993 fungierte der Lusterboden als regelmäßige Spielstätte des Hauses. Seit 1993 verbietet das Veranstaltungsgesetz das öffentliche Bespielen von Theaterräumen, die sich höher als 8 Meter über dem Straßenniveau befinden. Schließlich wurde der Lusterboden nach der Wiedereröffnung des Raums am Schwarzenbergplatz erneut als Probebühne verwendet, wozu er auch gegenwärtig dient. +Eine ungewöhnliche Spielstätte hatte die Inszenierung Der Anatom von Klaus Pohl mit Ignaz Kirchner. Sie fand im Anatomischen Saal der Akademie der Bildenden Künste am Schillerplatz statt (2005–2006). +Die außergewöhnliche Inszenierung von Letzter Aufruf von Albert Ostermaier, der ersten Zusammenarbeit von Andrea Breth mit dem Bühnenbildner von Martin Kušej, Martin Zehetgruber, wurde auf der Probebühne 1 im Arsenal im 3. Bezirk gespielt, die kurzfristig zu einem Theaterraum umgebaut wurde (2002). Auf derselben Probebühne fanden im Juni 2010 drei Vorstellungen von Christoph Schlingensiefs letztem Theaterstück Via Intolleranza II statt. +Eine besondere Spielstätte bot die Feststiege des Burgtheaters Christian Nickels Inszenierung Die Wand nach dem Roman von Marlen Haushofer im Dezember 2012. +Eine weitere Probebühne befindet sich in der Turnergasse im 15. Gemeindebezirk. +Die Wiener und „ihre“ Burg[Bearbeiten] + +Burgtheater, Hauptportal am Universitätsring + +Seitenansicht von Süden; in der ehemaligen Vorfahrt zur Kaiserstiege befindet sich das Restaurant „Vestibül“ + +Rückseite des Burgtheaters an der Löwelstraße + +Blick vom Dach über den südlichen Seitenflügel auf Volksgarten und Museen +Das Burgtheater stand für die Wiener schon immer im Rampenlicht. Es galt stets als besonders vornehm, „in die Burg“ zu gehen. Bereits im 19. Jahrhundert gehörten die Gerüchte und die Skandale um die Burgschauspieler zu den beliebtesten Themen der Wiener. In der Burg konnten sich die verschiedenen gesellschaftlichen Schichten (Bürgertum und Adel) treffen, obwohl ihre Plätze strikt voneinander getrennt waren. Die Burgschauspieler „verbanden“ die zwei Stände und genossen dadurch in Wien einen besonders hohen sozialen Status (siehe später Vorhangverbot). + +Die Schauspielerin Charlotte Wolter beispielsweise wurde geradezu hysterisch gefeiert, ihre Stimme – der kräftige „Wolter-Schrei“ – war legendär. Später, in den 1940er Jahren, war natürlich das Ehepaar Paula Wessely und Attila Hörbiger Publikumsliebling Nummer 1. „Die Wessely“ wurde von den Damen gern nachgeahmt, ihre Frisur, der „Wessely-Scheitel“, machte Mode.[30] Die Popularität der beiden wurde aber auch zu Propagandazwecken missbraucht, als sie sich für den Vollzug des Anschlusses einsetzten. Die Töchter des Ehepaares, die später alle Schauspieler geworden sind, litten oft unter dem Ruhm ihrer Eltern. + +„Die Burg“ geriet manchmal allerdings auch in negative Schlagzeilen. Im Vorfeld der Uraufführung von Thomas Bernhards Heldenplatz 1988 fühlten sich viele Österreicher in ihrer Ehre gekränkt, weshalb die als Protest dagegen gedachte Großaktion von Martin Humer, der Kuhmist vor dem Burgtheater ablud, bei vielen Gefallen fand. Ebenfalls wenig beeindruckt waren viele Wiener von der Performance von Hermann Nitsch im Jahr 2005. + +Beerdigungen berühmter Burgschauspieler sind nach wie vor ein gern besuchtes Ereignis, die Wiener lieben „die schöne Leich“. Diese Eigenschaft der Wiener wurde allerdings im musikalischen Stück Pompes Funèbres von Franz Wittenbrink auf der Bühne karikiert. Besonders große Ereignisse waren 1981 das Begräbnis von Paul Hörbiger und 1996 die Verabschiedung von Josef Meinrad, zu denen Tausende aus ganz Österreich angereist sind. Meinrad war so beliebt, dass der Platz zwischen dem Burgtheater und dem Volksgarten nach ihm benannt wurde.[31] + +Während heutzutage andere Theater nicht selten ums Überleben kämpfen müssen, scheint die Lust der Wiener, in die Burg zu gehen, ungebrochen zu sein. Die Auslastung des Hauses betrug in der Saison 2005/06 bei 313.000 Besuchern 84 Prozent. Das Einnahmen-Soll wurde um 380.000 € übertroffen, insgesamt wurden sechs Millionen Euro eingespielt. + +Ein großes Gesprächsthema der Wiener ist immer die Ernennung eines neuen Intendanten – meistens beginnt die Spekulation über die Person des möglichen Direktors schon Monate vor der Entscheidung, die vom jeweiligen Staatssekretär für Kultur und Medien bekanntgegeben wird und in der Regel noch monatelang für weiteren Gesprächsstoff sorgt. + +Im Hauptgebäude des Theaters befinden sich zwei Unternehmen, die zwar nicht zum Burgtheater gehören, aber mittlerweile zu „Institutionen“ geworden sind. Das Buchgeschäft Leporello befindet sich auf der linken Seite der Eingangshalle und führt nebst Büchern auch Geschenksgegenstände des Burgtheaters sowie signierte Szenenphotos. Es sperrt in der Regel eine Stunde vor Vorstellungsbeginn auf und bleibt bis Vorstellungsende geöffnet. Im rechten, südlichen Flügel des Theaters ist das Nobelrestaurant Vestibül untergebracht, das ein architektonisches „Spiegelbild“ der gleichnamigen Spielstätte im linken Flügel des Gebäudes und vor allem für sein Weinangebot bekannt ist. Im Restaurant sind, ähnlich wie im Café Landtmann, vor und nach der Vorstellung oft Schauspieler und Theaterleute anzutreffen. + +Das Burgtheater ist auf der Rückseite der 50-Schilling-Banknote von 1970 zu sehen. Es ist auch wiederholt Motiv österreichischer Münzen und Briefmarken. + +Das „Burgtheaterdeutsch“[Bearbeiten] +Das Burgtheaterdeutsch, die Sprache, die auf der Bühne des Burgtheaters gesprochen wird, empfinden die meisten Wiener wie Musik in den Ohren, auf jeden Fall wird diese Bezeichnung für eine besonders schön gesprochene Variante der (im süddeutschen Sprachraum gebräuchlichen) deutschen Sprache verwendet. Diese Variante war eigentlich eine Kunstsprache und diente dazu, dass die Zuschauer die Schauspieler, die aus unterschiedlichen Regionen des deutschen Sprachraums kamen, auch unter den nicht idealen akustischen Umständen des Burgtheaters verstehen konnten. Als klassisches Beispiel für Burgtheaterdeutsch nennen viele die Bühnensprache, die Paula Wessely verwendete. + +Die großen Namen und ihre Wirkung[Bearbeiten] +Mittlerweile stammt ein großer Teil der Schauspieler und Theatermitarbeiter nicht aus Österreich, sondern aus Deutschland oder anderen Ländern; dennoch werden viele Burgschauspieler von den Wienern als Wiener akzeptiert und als „ihre Schauspieler“ verehrt. Der Deutsche Michael Heltau ist einer der größten Wienerlied-Interpreten, und Robert Meyer, der aus dem Grenzgebiet von Deutschland zu Österreich stammt, ist einer der beliebtesten Nestroy-Darsteller. Die Schweizerin Annemarie Düringer gehört ebenso zu den Lieblingen des Publikums wie der Deutsche Ignaz Kirchner, und die gebürtige Deutsche Susi Nicoletti galt als die österreichische Schauspielerin schlechthin. Auch die von Claus Peymann nach Wien geholten und anfangs angefeindeten Schauspieler wie Gert Voss und Kirsten Dene wurden bald Publikumslieblinge. Eine gute Besetzung (manchmal mit Gastschauspielern) kann bewirken, dass es so gut wie unmöglich ist, für eine Produktion Karten zu bekommen. Die Namen der schon erwähnten Hörbigers und „der Wessely“ wirkten wie ein Magnet auf das Publikum, es war praktisch alles restlos ausverkauft, wo sie auftraten. Aber auch heute gibt es „Dauerbrenner“: für die Ottokar-Inszenierung mit „der Orth“, „dem Maertens“, „dem Merkatz“ und „dem Moretti“ oder den Nathan mit „dem Brandauer“ war es monatelang sehr schwer, ohne Abo Karten zu kaufen. Die Beiträge im Gästebuch der Burgtheater-Homepage zeugen davon, dass manche Inszenierungen eine richtige Fan-Gemeinde haben. Dennoch kommt es immer wieder vor, dass die konservativeren Burgbesucher bei einer modernen Inszenierung ihren Unmut während der Vorstellung lautstark ausdrücken. + +Ein Haus mit Tradition[Bearbeiten] +Der natürlich auch anderswo verbreitete spezielle Theater-Aberglaube ist auch im Burgtheater, wo auf Tradition ein besonders großer Wert gelegt wird, anzutreffen, und daraus resultierende Bräuche und Rituale werden stets eingehalten. Viele Schauspieler glauben sogar – mit einem gewissen Augenzwinkern –, dass das Haus einen „Hausgeist“ hat. + +Es gibt strikte Hausregeln, zum Beispiel solche, die die Verbeugung regeln. Die Verbeugungsordnung schreibt vor, wer, wann und mit wem sich verbeugen soll, mit Sonderregeln für die Premiere. Eine solche Regel ist angeblich zum Beispiel, dass alle, die im zweiten Akt spielen, sich verbeugen müssen, diejenigen, die nur im ersten Akt auftreten, können es natürlich auch tun, müssen aber nicht. Bei der Premiere verbeugen sich in der Regel alle Mitwirkenden, auch die Komparsen und Kinderdarsteller. Für besondere Ensemblemitglieder galten manchmal andere Regeln, so musste sich zum Beispiel der alte Paul Hörbiger nicht immer mit den anderen verbeugen, weil er sonst seinen Zug verpasst hätte.[32] + +Das sogenannte Vorhangverbot war ein ungeschriebenes Gesetz, das fast 200 Jahre eingehalten wurde. Es geht auf eine polizeiliche Theaterordnung vom 19. August 1798 zurück, die vorschrieb, dass sich vor dem Vorhang nur Gäste und Debütanten, aber keine Ensemblemitglieder verbeugen durften. Der Grund war das hohe Ansehen der Schauspieler, sie galten als „Schauspieler Seiner Majestät“ und als solche wäre es für sie unmöglich gewesen, sich vor dem gemeinen Volk zu verbeugen.[33] Das Vorhangverbot, dessen Abschaffung im Lauf der Zeit immer wieder diskutiert wurde, das auch nicht lückenlos eingehalten wurde – etwa bei Aufführungen für Kinder – und nur für das Haupthaus (also nie für das Akademietheater) galt, wurde mit Beginn der Saison 1983/1984 vom damaligen Unterrichtsminister Helmut Zilk aufgehoben. Die erste Premiere ohne Vorhangverbot war Nestroys Höllenangst in der Inszenierung von Leopold Lindtberg. + +Repertoire, Programm und Publikum[Bearbeiten] +Das Burgtheater arbeitet im Repertoiresystem, das heißt in jeder Saison werden mindestens 30 Stücke abwechselnd gespielt. Jährlich gibt es im Burgtheater, Akademietheater und in den kleinen Spielstätten etwa Premieren. + +In den ersten Jahrzehnten war das Repertoire des Burgtheaters, also der Umfang der gespielten Stücke, sehr groß. In der Direktion Laube konnten zum Teil bis zu 160 verschiedene Stücke pro Saison gesehen werden, und noch zu Anfang der Saison 1918/1919 waren es 107 Stücke. Einige Inszenierungen hielten sich oft 10 Jahre oder länger, manche sogar über Jahrzehnte hinweg, sowohl im alten als auch im neuen Burgtheater auf dem Spielplan. Dafür wurde sie pro Saison höchstens 4 bis 6 Mal gezeigt. Somit mussten Abonnenten nicht allzu oft dasselbe Stück sehen, sondern waren mit einer außergewöhnlich abwechslungsreichen Vielfalt konfrontiert. Dieses System endete nach dem Ersten Weltkrieg. Plötzlich standen im Repertoire der Saison 1919/20 nur noch 20 Stücke zur Verfügung. Als die Regie in den Vordergrund rückte sowie Inszenierungen durch wechselnde Moden schneller veralteten, wurden Stücke pro Jahr mindestens so oft angesetzt wie früher in 10 oder 20 Jahren. + + +Ein typisches Burgtheaterplakat +Das aktuelle Programm des Burgtheaters wird auf Plakaten und einer roten Tafel links vom Haupteingang angekündigt. Früher – vor Bachlers Zeit – war es üblich, das Programm an die Fassade über dem Haupteingang zu hängen. Die Plakate werden jeden Tag mit der aktuellen Besetzung gedruckt und während der Vorstellung am Vorabend aufgehängt; sie enthalten auch die Namen der Komparsen (bei Mehrfachbesetzungen immer die aktuelle Besetzung). + +Die Programmhefte besaßen nach dem Zweiten Weltkrieg ein einheitliches Aussehen, das für alle Bundestheater galt: sie waren auf der Vorderseite durch eine Reihe eng gesetzter, brauner, senkrechter Linien gekennzeichnet, auf der unteren Mitte war in kursiver Schrift der Name des Theaters angegeben. In die Programmhefte wurden die Theaterzettel eingelegt. Sie wurden täglich für die jeweiligen Vorstellungen gedruckt und enthielten u. a. Angaben zu Stück, Autor, Beginn, Ende und Besetzung. Nach dem Aufkommen der Programmhefte wurden sie in diese eingelegt. Dieses System wurde bis 1986 beibehalten. Mit dem Beginn der Direktion Peymann wurde dieses System nach und nach abgeschafft, die früher üblichen häufigen Umbesetzungen waren im Lauf der Jahre durch konstante Besetzungen abgelöst worden. Nunmehr war die jeweilige Besetzung fix im Programmheft abgedruckt. Eventuelle Änderungen werden durch eingelegte, kleinere Zettel bekanntgegeben („In der heutigen Vorstellung spielt N. N. die Rolle XY“). + +Die Programmhefte enthielten neben (kultur)historischen Texten und Informationen über Werk und Autor seit der Direktion Peymann auch zumeist den gesamten Text des aufgeführten Stückes, in dem die Änderungen, Kürzungen und Regieanweisungen markiert waren. Gelegentlich wurden auch Fotos von den Bühnenbildentwürfen oder -modellen sowie den Kostümfigurinen abgedruckt. + +Ältere Programmhefte haben einen Sammelwert und können an besonderen Tagen (wie am Tag der offenen Tür) im Burgtheater käuflich erworben werden. In der Peymann-Direktion wurde das Aussehen der Programmhefte von Karl-Ernst Herrmann neu gestaltet. Sie waren für das Burgtheater und das Akademietheater grundsätzlich ähnlich gehalten und unterschieden sich in den ersten Jahren nur durch eine andere Farbgebung (hellgrau für das Akademietheater, helles Beige für die Burg). Später wurde mit anderen Farbgebungen sowie unterschiedlichen Formaten experimentiert. Lediglich das Programmheft für André Hellers Sein und Schein unterschied sich komplett von den übrigen Programmheften und enthielt Illustrationen der an der Ausstattung beteiligten Künstler (Roy Lichtenstein oder Mimmo Paladino). Unter Bachlers Direktion erhielten die Programmhefte grundsätzlich individuelle Outfits und sie enthalten meistens assoziative Texte und Bilder zum Stück, nur ganz selten den Text des Stückes. Die Plakate und die Programmhefte des Burgtheaters werden in der Druckerei agensketterl in Mauerbach (NÖ) hergestellt. + +Das Repertorium war die Sammlung der seit 1821 angefertigten Dokumentation der Aufführungen am Burgtheater. In große Bücher wurden täglich die Aufführungen und bei Premieren die Besetzungen eingetragen. Alle Schauspieler, die später eine Rolle in dem jeweiligen Stück übernahmen, wurden ergänzt. Für Inszenierungen, die vor 1821 auf dem Spielplan standen und noch gespielt wurden, trug man die Besetzungen seit 1776 nach. Jene Stücke, die bis 1821 vom Spielplan verschwanden, blieben hingegen unberücksichtigt. Quellen hierzu sind Theater- und Programmzettel oder alte Theaterzeitschriften. Die Führung des Repertoriums wurde 1958 aufgegeben. Ihnen folgten die Vorstellungsplatten nach. Sie wurden von der Regiekanzlei für jede Inszenierung eines Stücks angelegt und enthielten die Aufführungsdaten, die Besetzungen sowie allfällige Umbesetzungen. + +Im jährlichen Geschäftsbericht des Burgtheaters kann man die genauen Besetzungs- und Umbesetzungslisten, weiters Statistiken über die Auslastung des Hauses bei diversten Produktionen finden. + +Um einen direkten Kontakt mit dem Publikum aufrechtzuerhalten, veranstaltet das Burgtheater regelmäßig öffentliche Publikumsgespräche – teils allgemeine, bei denen die Zuschauer die Möglichkeit bekommen, der Direktion Fragen zu stellen, teils spezielle Publikumsgespräche zu einzelnen Inszenierungen, die immer im Anschluss einer Vorstellung stattfinden, und bei denen das Publikum die Dramaturgie, den Regisseur und die Schauspieler treffen kann. Matinées und Lesungen bereiten wichtige Ereignisse vor, wie Premieren, und auf Einträge im Gästebuch der Homepage wird auch geantwortet. + +Abonnements, Kartenvorverkauf, Spielzeiten[Bearbeiten] +Von 1776 bis in die Zeit nach dem Ersten Weltkrieg existierte kein Abonnementsystem im heutigen Sinne. Es gab die sogenannten Stammsitze in allen Teilen des Zuschauerraums. Sie berechtigten zum täglichen Besuch des Burgtheaters und zur Benutzung eines bestimmten Sitzes. Aufgrund der Stammsitze musste der Spielplan besonders abwechslungsreich sein. Oft wurden in einer einzigen Saison mehr als 100 verschiedene Werke gezeigt. Beliebte Stücke konnten Jahr für Jahr immer wieder einige Male angesetzt werden, teilweise über Jahrzehnte hinweg in derselben Inszenierung. Die Regie spielte jedoch damals eine deutlich untergeordnete Rolle. Um das Interesse an den Aufführungen zu erhöhen, fanden zudem häufige Umbesetzungen statt. Ein ähnliches System bietet das Burgtheater zurzeit im Rahmen des Festabonnements an. Neben diesen Vollabonnements gab es auch Halbabonnements (sie berechtigten zum Besuch an geraden oder ungeraden Tagen) sowie Viertelabonnements (Besuch an jedem vierten Tag). Durch die radikale Einschränkung des bis 1919/20 zahlenmäßig großen Repertoires wurde dieses System obsolet. Ab 25. November 1919 wurde das Vollabonnement auf Galeriesitze aufgelassen, außerdem auch das Viertelabonnement auf Parkettsitze. Den Halbabonnenten wurde das Besuchsrecht für einen Tag entzogen, womit mehr Karten in den freien Verkauf gelangten. + +Zurzeit gibt es 30 verschiedene Abonnements und diverse Zyklen (wie der Zyklus Nach der Premiere). Das Wahlabonnement berechtigt den Inhaber, zu günstigeren Preisen schon vor dem offiziellen Vorverkaufsbeginn Karten einer gewissen Kategorie zu erwerben. Viele Vorstellungen werden auch im Jugendabo „Theater der Jugend“ angeboten. Für Senioren gibt es ein eigenes Abonnement, bei dem einmal im Monat eine Vorstellung angeboten wird, die früher (um 16 oder 17 Uhr) beginnt. Das Festabonnement berechtigt den Inhaber, fünf Vorstellungen seiner Wahl an einem vorher festgelegten Tag der Woche (außer Samstag kann man jeden beliebigen Tag wählen) mit großer Preisermäßigung zu besuchen – der Aboinhaber hat bei diesem Abonnement einen fixen Sitzplatz. + +An jedem 20. des Monats beginnt der Kartenvorverkauf für die Vorstellungen des nächsten Monats, Wahlaboinhaber können bereits ab dem 15. des Monats Karten reservieren. Gäste aus anderen Bundesländern und aus dem Ausland können auch schriftlich oder per Fax Karten bestellen. Es gibt Kontingente für Pädagogen und Jugendliche, seit Jänner 2007 ist es sogar möglich, für gewisse Vorstellungen mit anschließendem Gespräch Gratiskarten für ganze Schulklassen zu bekommen.[34] Eine Stunde vor Vorstellungsbeginn kann man Restkarten zum halben Preis kaufen, und es werden immer Stehplatzkarten zurückgehalten, die ebenfalls vor Vorstellungsbeginn angeboten werden, bei sehr begehrten Vorstellungen kann man jedoch nur jeweils eine Stehplatzkarte pro Person kaufen. + + +Sitzplan +Das Burgtheater und seine Nebenbühnen werden von Mitte September bis zum 30. Juni theoretisch jeden Tag bespielt. Bis zur Direktion Bachler begann das Burgtheater jährlich am 1. September mit dem Spielbetrieb (nach einer zweimonatigen Sommerpause). Generell spielfrei sind nur der Karfreitag und der Heilige Abend, probebedingt kann es vorkommen, dass an einigen Abenden auf der einen oder der anderen Bühne keine Vorstellung stattfindet. Diese sogenannten Schließtage zur ganztägigen Abhaltung von Bühnen-, Dekorations- und Beleuchtungsproben im Burgtheater sowie im Akademietheater wurden erstmals unter der Direktion Peymann eingeführt und sorgten einige Jahre lang für heftige Kontroversen, die zum Teil auf den Kultur- und Leserbriefseiten österreichischer Zeitungen ausgetragen wurden. Peymann wurde vorgeworfen, durch Schließtage die Einnahmen des Burgtheaters zu reduzieren. + +Eine große Debatte löste im Februar 2007 die Nachricht aus, dass im Juni 2008 eine Fan-Meile zur 13. Fußball-Europameisterschaft vor dem Rathaus – und somit auch vor dem Burgtheater – errichtet werden soll, und das Burgtheater fordert eventuelle Ersatzspielstätten, damit der Spielbetrieb nicht beeinträchtigt wird und keine Schließtage erforderlich sind.[35] + +Die Gesellschaft der Freunde des Burgtheaters[Bearbeiten] +Die Gesellschaft der Freunde des Burgtheaters ist eine als eingetragener Verein wirkende Publikumsorganisation, die 1956 von ungefähr 200 Theaterliebhabern gegründet wurde und in der Goethegasse im 1. Bezirk Wiens ihren Sitz hat. Unter den Gründern waren auch berühmte Persönlichkeiten wie Friedrich Heer und Clemens Holzmeister. Seitdem erhöhte sich die Mitgliedschaft auf etwa 700 Personen. Der Gesellschaft steht ein eigenes Theaterkontingent mit fixen Plätzen für die erste Vorstellung nach jeder Premiere auf allen Spielstätten des Theaters zur Verfügung. Der Verein pflegt einen intensiven Kontakt zum Haus und zu den Schauspielern. Er organisiert Publikumstreffen, Lesungen, Buchpräsentationen und Informationsabende für seine Mitglieder, weiters versucht er auch das junge Publikum anzusprechen, indem er versucht, beliebte Nachwuchskünstler für diese Veranstaltungen zu engagieren. Die Gesellschaft unterstützt auch das Studium talentierter Jungschauspieler am Max Reinhardt Seminar und schreibt manchmal Schreibwettbewerbe aus. + +Mitarbeiter am Burgtheater[Bearbeiten] +Das Ensemble[Bearbeiten] +Zu den kaiserlichen Zeiten genossen die Schauspieler einen hohen gesellschaftlichen Rang und ein großes Ansehen. Sie wurden meistens auf Lebenszeit angestellt. Heute gibt es für Ensemblemitglieder meistens Jahresverträge. Seit Oktober 1971 gibt es die Richtlinien für die Tätigkeit der Ensemblevertretung des Burgtheaters.[36] Ein von Ensemble gewählter Vertrauensmann hat gegenüber der Direktion das Recht, unter anderem bei Besetzungen und bei der Spielplangestaltung mitzusprechen. Der derzeitige Ensemblesprecher ist Roland Koch.[37] Das Burgtheater ist grundsätzlich ein typisches Ensembletheater, die meisten Schauspieler sind mit längerfristigen Verträgen gebunden, Gäste kommen nur für einzelne Rollen. Zugleich lebte das Burgtheater immer schon von herausragenden Schauspielern, die nur für eine einzige oder ein paar Rollen ans Burgtheater kamen und sich mit ihrer Persönlichkeit einbrachten. + +Derzeitige Ensemblemitglieder[Bearbeiten] +In der Saison 2014/2015 sind am Burgtheater 74 Schauspieler als Ensemblemitglieder und weitere 38 als Gäste engagiert. Zu den aktuell 112 Schauspielern (44 Damen, 68 Herren) gehören als Ensemblemitglieder:[38] + +Damen: Liliane Amuat, Elisabeth Augustin, Jasna Fritzi Bauer, Andrea Clausen, Kirsten Dene, Stefanie Dvorak, Sarah Viktoria Frick, Alina Fritsch, Regina Fritsch, Brigitta Furgler, Frida-Lovisa Hamann, Maria Happel, Dorothee Hartinger, Sabine Haupt, Alexandra Henkel, Mavie Hörbiger, Katharina Lorenz, Dörte Lyssewski, Petra Morzé, Elisabeth Orth, Caroline Peters, Barbara Petritsch, Christiane von Poelnitz, Stefanie Reinsperger, Sylvie Rohrer, Aenne Schwarz, Dunja Sowinetz, Catrin Striebeck, Adina Vetter, Johanna Wokalek. +Herren: Bernd Birkhahn, Klaus Maria Brandauer, Franz J. Csencsits, Sven Dolinski, Detlev Eckstein, Lucas Gregorowicz, Philipp Hauß, Michael Heltau, Tino Hillebrand, Daniel Jesch, Marcus Kiepe, Ignaz Kirchner, Peter Knaack, Hans Dieter Knebel, Roland Koch, Dietmar König, Johannes Krisch, Fabian Krüger, Michael Maertens, Oliver Masucci, Michael Masula, Peter Matić, Rudolf Melichar, André Meyer, Markus Meyer, Joachim Meyerhoff, Tilo Nest, Dirk Nocker, Johann Adam Oest, Nicholas Ofczarek, Klaus Pohl, Robert Reinagl, Martin Reinke, Falk Rockstroh, Laurence Rupp, Branko Samarovski, Hermann Scheidleder, Martin Schwab, Peter Simonischek, Oliver Stokowski, Daniel Sträßer, Stefan Wieland, Peter Wolfsberger, Martin Wuttke. +Zu den Gästen der Spielzeit 2014/15 zählen: + +Damen: Inge van Bruystegem, Edith Clever, Gertraud Jesserer, Sung Im Her, Corinna Kirchhoff, Pauline Knof, Melanie Kretschmann, Sona MacDonald, Nadia Migdal, Birgit Minichmayr, Wiebke Mollenhauer, Sophie Rois, Yohanna Schwertfeger, Bibiana Zeller. +Herren: Gundars Āboliņs, Sven-Eric Bechtolf, Joachim Bißmeier, Gregor Bloéb, August Diehl, Marc Hosemann, Gerrit Jansen, Simon Kirsch, Gerhard König, Michael König, Christoph Krutzler, Christoph Luser, Matthias Matschke, Cornelius Obonya, Sven Philipp, Hanno Pöschl, Hans-Michael Rehberg, Thomas Reisinger, Michael Rotschopf, Udo Samel, Albrecht Abraham Schuch, Maik Solbach, Florian Teichtmeister, Moritz Vierboom. +Saison 2011/2012[Bearbeiten] +In der Saison 2011/2012 waren am Burgtheater 80 Schauspieler als Ensemblemitglieder und weitere 40 als Gäste engagiert. Zu den 120 Schauspielern (44 Damen, 76 Herren) gehörten als Ensemblemitglieder: Liliane Amuat, Elisabeth Augustin, Sven-Eric Bechtolf, Bernd Birkhahn, Klaus Maria Brandauer, Andrea Clausen, Franz J. Csencsits, Kirsten Dene, Sven Dolinski, Annemarie Düringer, Stefanie Dvorak, Detlev Eckstein, Sarah Viktoria Frick, Regina Fritsch, Brigitta Furgler, Lucas Gregorowicz, Maria Happel, Dorothee Hartinger, Sabine Haupt, Philipp Hauß, Michael Heltau, Alexandra Henkel, Mavie Hörbiger, Gerrit Jansen, Daniel Jesch, Marcus Kiepe, Corinna Kirchhoff, Ignaz Kirchner, Simon Kirsch, Peter Knaack, Hans Dieter Knebel, Roland Koch, Dietmar König, Michael König, Johannes Krisch, Fabian Krüger, Katharina Lorenz, Dörte Lyssewski, Michael Maertens, Oliver Masucci, Michael Masula, Peter Matić, Juergen Maurer, Rudolf Melichar, André Meyer, Markus Meyer, Joachim Meyerhoff, Peter Miklusz, Birgit Minichmayr, Blanka Modra, Petra Morzé, Tilo Nest, Dirk Nocker, Johann Adam Oest, Nicholas Ofczarek, Elisabeth Orth, Caroline Peters, Barbara Petritsch, Christiane von Poelnitz, Klaus Pohl, Robert Reinagl, Martin Reinke, Falk Rockstroh, Sylvie Rohrer, Branko Samarovski, Udo Samel, Hermann Scheidleder, Martin Schwab, Yohanna Schwertfeger, Peter Simonischek, Dunja Sowinetz, Daniel Sträßer, Catrin Striebeck, Adina Vetter, Moritz Vierboom, Stefan Wieland, Johanna Wokalek, Peter Wolfsberger, Martin Wuttke, Bibiana Zeller. + +Zu den Gästen der Spielzeit 2011/12 zählen: Therese Affolter, Elizabeth Conner, Anne Gridley, Jana Horst, Melanie Kretschmann, Julie LaMendola, Sandra Lipp, Sunnyi Melles, Karin Pfammatter, Elisa Plüss, Katharina Schmalenberg, Anna Starzinger, Bettina Stucky, Merle Wasmuth; Gundars Āboliņs, Juris Baratinskis, Marcus Bluhm, Markus Hering, Marc Hosemann, Robert Hunger-Bühler, Robert M. Johanson, Manfred Karge, Roland Kenda, Christoph Luser, Paulus Manker, Matthias Matschke, Tobias Moretti, Jacques Palminger, Kaveh Parmas, Hanno Pöschl, Jörg Ratjen, Hans-Michael Rehberg, Thomas Reisinger, Veit Schubert, Edgar Selge, Maik Solbach, Volker Spengler, Oliver Stokowski, Ernst Stötzner, Gerd Wameling. + +Ehemalige Ensemblemitglieder[Bearbeiten] + +Max Devrient als Zawisch in Franz Grillparzers „König Ottokars Glück und Ende“ nach 1891. +Berühmte ehemalige Ensemblemitglieder: Erich Aberle, Trude Ackermann, Rosa Albach-Retty, Wolf Albach-Retty, Ernst Anders, Raoul Aslan, Blanche Aubry, Erich Auer, Ewald Balser, Günther Georg Bauer, Bernhard Baumeister, Patrick O. Beck, Maria Becker, Klaus Behrendt, Ulrike Beimpold, Anne Bennent, Achim Benning, Joachim Bissmeier, Hedwig Bleibtreu, Monica Bleibtreu, Karl Blühm, Marcus Bluhm, Karl Böhm, Uwe Bohm, Otto Bolesch, Markus Boysen, Rolf Boysen, Viktor Braun, Marion Breckwoldt, Inge Brücklmeier, Traugott Buhre, Gandolf Buschbeck, Horst Caspar, Karim Chérif, Bruno Dallansky, Theodor Danegger, Ernst Deutsch, Max Devrient, Birgit Doll, Käthe Dorsch, Lona Dubois, Margarethe Dux, Thomas Egg, Hartmut Ehler, Heinz Ehrenfreund, Karl Eidlitz, Maria Eis, Christine Enghaus, Richard Eybner, Ulli Fessl, O. W. Fischer, Sebastian Fischer, Georg Filser, Peter Fitz, Ludwig Gabillon, Zerline Gabillon, Bruno Ganz, Wolfgang Gasser, Helma Gautier, Gerhard Geisler, Adrienne Gessner, Siegmund Giesecke, Alexander Girardi, Boy Gobert, Käthe Gold, Hugo Gottschlich, Fritz Grieb, Ingeborg Gruber, Karlheinz Hackl, Günther Haenel, Carla Hagen, Amalie Haizinger, Fritz Hakl, Konrad Adolf Hallenstein, Paul Hartmann, Heidemarie Hatheyer, Angelika Hauff, Wolfgang Hebenstreith, Urs Hefti, Fred Hennings, Jürgen Hentsch, Miguel Herz-Kestranek, Philipp Hochmair, Elisabeth Höbarth, Attila Hörbiger, Christiane Hörbiger, Paul Hörbiger, Frank Hoffmann, Paul Hoffmann, Stella von Hohenfels-Berger, Thomas Holtzmann, Judith Holzmeister, Gusti Huber, Wolfgang Hübsch, Manfred Inger, Helmut Janatsch, Antonie Janisch, Michael Janisch, Julia Janssen, Hanns-Ernst Jäger, Gertraud Jesserer, Peter P. Jost, Curd Jürgens, Josef Kainz, Elisabeth Kallina, Lilly Karoly, Otto Kerry, Lisl Kinast, Pauline Knof, Inge Konradi, Willi Kowalj, Hilde Krahl, Friedrich Krastel, Josef Krastel, Tom Krinzinger, Ida Krottendorf, Karl Friedrich Krüger, Jutta Lampe, Pavel Landovský, Jenny Lattermann, Inge Leddihn, Fritz Lehmann, Lotte Ledl, Joseph Lewinsky, Florian Liewehr, Fred Liewehr, Hugo Lindinger, Robert Lindner, Theo Lingen, Paola Loew, Else Ludwig, Sylvia Lukan, Ferdinand Maierhofer, Leslie Malton, Paulus Manker, Sigrid Marquardt, Johanna Matz, Josef Meinrad, Kurt Meisel, Karl Wilhelm Meixner, Rudolf Melichar, Robert Meyer, Wolfgang Michael, Erna Michall, Karl Mittner, Nick Monu, Heinz Moog, Hans Moser, Ulrich Mühe, Hans Günther Müller, Fritz Muliar, Alfred Neugebauer, Dorothea Neff, Susi Nicoletti, Ruth Niehaus, Cornelius Obonya, Hanns Obonya, Joseph Offenbach, Max Ophüls, Elfriede Ott, Dorothea Parton, Karl Paryla, Romuald Pekny, Denis Petkovic, Max Pfeiler, Hedwig Pistorius, Erika Pluhar, Ernst Princz, Ulla Purr, Will Quadflieg, Charles Regnier, Emerich Reimers, Heinz Reincke, Ulrich Reinthaller, Veit Relin, Walther Reyer, Tonio Riedl, Hilde Rom, Otto Rub, Albert Rueprecht, Heinz Rühmann, Johanna Sacco, Adele Sandrock, Johannes Schauer, Fritz Schediwy, Erich Schellow, Hannes Schiel, Aglaja Schmid, Otto Schmöle, Wenzel Scholz, Hermann Schöne, Peter Schratt, Lieselotte Schreiner, Joseph Schreyvogel, Heinrich Schweiger, Alma Seidler, Albin Skoda, Stefan Skodler, Adolf von Sonnenthal, Edd Stavjanik, Sigfrit Steiner, Wolfgang Stendar, Lilly Stepanek, Lena Stolze, Peter Striebeck, Walter Stumvoll, Sonja Sutter, Michael Tellering, Johannes Terne, Hans Thimig, Helene Thimig, Hermann Thimig, Hugo Thimig, Curth Anatol Tichy, Jane Tilden, Lotte Tobisch, Heinz Trixner, Alexander Trojan, Eckart Uhlmann, Gertrud Ukena, Gert Voss, Hilde Wagener, Rudolf von Waldenfels, Martha Wallner, Brigitte Walzl Peter Weck, Antje Weisgerber, Angelika Welzl Oskar Werner, Paula Wessely, Josef Wichart, Jürgen Wilke, Heinz Woester, Gusti Wolf, Paul Wolf-Plottegg, Charlotte Wolter, Klausjürgen Wussow, Philipp Zeska, Eleonore Zetzsche, Eva Zilcher, Kurt Zips, Heinz Zuber. + +Gastschauspieler[Bearbeiten] +Als Gäste, für einzelne Rollen engagiert, traten auf Meriam Abbas, Therese Affolter, Susanne Almassy, Axel von Ambesser, Leon Askin, Barbara Auer, Bibiana Beglau, Senta Berger, Josef Bierbichler, Hans-Christian Blech, Pinkas Braun, Ella Büchi, Margit Carstensen, Ingrid Caven, Edith Clever, August Diehl, Ralf Dittrich, Karoline Eichhorn, Veronika Fitz, Cornelia Froboess, Helmut Griem, Olivia Grigolli, Matthias Habich, Corinna Harfouch, O. E. Hasse, Hannelore Hoger, Marianne Hoppe, Christine Kaufmann, Hermann Killmeyer, Klaus Kinski, Wolfram Koch, Jutta Lampe, Hermann Lause, Helmuth Lohner, Susanne Lothar, Eva Mattes, Sunnyi Melles, Kurt Meisel, Karl Merkatz, Bernhard Minetti, Tobias Moretti, Richard Münch, Dierk Prawdzik, Hans Michael Rehberg, Martin Reinke, Hans Christian Rudolph, Ilse Ritter, Sophie Rois, Otto Sander, Maximilian Schell, Otto Schenk, Christoph Schlingensief, Walter Schmidinger, Robert Stadlober, Oliver Stokowski, Tilda Swinton, Franziska Tilden, Susanne Tremper, Ulrich Tukur, Angela Winkler, Ulrich Wildgruber, Werner Wölbern, Gisela Uhlen, Walker Wyatt, Hans Dieter Zeidler. + +Ehrenmitglieder[Bearbeiten] +Ehrenmitglieder sind: Max Devrient 1922, Hugo Thimig 1922, Georg Reimers 1922, Auguste Wilbrandt-Baudius 1922, Hedwig Bleibtreu 1924, Rosa Albach-Retty 1928, Tiny Senders 1929, Anton Wildgans 1932, Else Wohlgemuth 1935, Raoul Aslan 1946, Erhard Buschbeck 1949, Werner Krauß 1959, Alma Seidler 1960, Adolf Rott 1962, Franz Salmhofer 1963, Fred Hennings 1963, Ewald Balser 1963, Ernst Lothar 1963, Eduard Volters 1964, Hermann Thimig 1965, Paula Wessely 1967, Käthe Gold 1967, Ernst Haeusserman 1968, Fred Liewehr 1969, Attila Hörbiger 1971, Josef Meinrad 1973, Leopold Lindtberg 1974, Rudolf Steinboeck 1978, Heinz Moog 1978, Susi Nicoletti 1983, Erich Auer 1986, Gusti Wolf 1987, Fritz Muliar 1995, Wolfgang Gasser 1997, Judith Holzmeister 2000, Heinrich Schweiger 2000, Annemarie Düringer 2001, Michael Heltau 2003, Klaus Maria Brandauer 2008, Gerhard Blasche 2008, Klaus Bachler 2009, Martin Schwab 2009, Gert Voss 2009, Sylvia Lukan 2010, Claus Peymann 2012, Elisabeth Orth 2014, Achim Benning, Gerhard Klingenberg. + +Regisseure am Burgtheater[Bearbeiten] +Direktion Röbbeling: Josef Gielen, Ernst Lothar, Otto Preminger, Herbert Waniek +Direktion Gielen: Axel von Ambesser, Raoul Aslan, Ewald Balser, Ulrich Bettac, Walter Davy, Leon Epp, Walter Felsenstein, Josef Gielen, Joseph Glücksmann, Curd Jürgens, Leopold Lindtberg, Theo Lingen, Ernst Lothar, Gustav Manker, Charles Regnier, Adolf Rott, Oscar Fritz Schuh, Hans Thimig, Berthold Viertel, Eduard Volters, Herbert Waniek, Oskar Wälterlin, Philipp Zeska +Direktion Rott: Josef Gielen, Adolf Rott +Direktion Haeusserman: Axel von Ambesser, Fritz Kortner, Gustav Rudolf Sellner, Rudolf Steinboeck, Gustav Manker, Leopold Lindtberg, Ernst Lothar +Direktion Paul Hoffmann: Boy Gobert,Gerhard Klingenberg, Kurt Meisel, Leopold Lindtberg, Adolf Rott, Otto Schenk, Rudolf Steinboeck +Direktion Klingenberg: Peter Arens, Erich Auer, Erwin Axer, Jean-Louis Barrault, Achim Benning, Edward Bond, Pinkas Braun, Kazimierz Dejmek, Dieter Dorn, Jaroslav Dudek, Bruno Felix, Walter Felsenstein, Karl Fruchtmann, Wolfgang Glück, Roberto Guicciardini, Peter Hall, Dietrich Haugk, Gerd Heinz, Gerhard F. Hering, Michael Kehlmann, Gerhard Klingenberg, Otomar Krejča, Wolfgang Liebeneiner, Leopold Lindtberg, Peter Lotschak, Conny Hannes Meyer, Mario Missiroli, Claus Peymann, Jean-Pierre Ponnelle, Adolf Rott, Jean-Paul Roussillon, Luca Ronconi, Otto Schenk, Hans Schweikart, Rudolf Steinboeck, Giorgio Strehler, Konrad Swinarski, Otto Tausig, Ernst Wendt, Rudolf Wessely, Herbert Wochinz, Peter Wood, Fritz Zecha +Direktion Benning: Erwin Axer, Achim Benning, Dieter Berner, Benno Besson, Adolf Dresen, Karl Fruchtmann, Armand Gatti, Dieter Giesing, Terry Hands, Hans Hollmann, Angelika Hurwicz, Gerhard Klingenberg, Thomas Langhoff, Leopold Lindtberg, Juri Ljubimow, Jonathan Miller, Jérôme Savary, Johannes Schaaf, Otto Schenk, Peter Wood, Horst Zankl +Direktion Peymann: Einar Schleef, Ruth Berghaus, Luc Bondy, Dieter Giesing, Michael Haneke, Matthias Hartmann, Leander Haußmann, Karin Henkel, Uwe Jens Jensen, Manfred Karge, Alfred Kirchner, Konstanze Lauterbach, Cesare Lievi, Paulus Manker, Wilfried Minks, Claus Peymann, Niels-Peter Rudolph, Giorgio Strehler, Philip Tiedemann, Peter Zadek, Tamás Ascher +Direktion Bachler: Stefan Bachmann, Igor Bauersima, Karin Beier, Theu Boermans, Andrea Breth, Nicolas Brieger, Barbara Frey, Klaus Michael Grüber, Sebastian Hartmann, Niklaus Helbling, Friederike Heller, Grzegorz Jarzyna, Stephan Kimmig, Martin Kušej, Thomas Langhoff, Kurt Palm, Carolin Pienkos, Christiane Pohle, Silviu Purcarete, Rimini Protokoll, Árpád Schilling, Christoph Schlingensief, Nicolas Stemann, Peter Zadek +Direktion Hartmann: Stefan Bachmann, Anna Bergmann, David Bösch, Jan Bosse, Luc Bondy, Andrea Breth, Kelly Copper und Pavol Liska, Barbara Frey, Dieter Giesing, Dimiter Gotscheff, Matthias Hartmann, Niklaus Helbling, Alvis Hermanis, Stephan Kimmig, Michael Laub, Jan Lauwers, Alexandra Liedtke, David Marton, Bastian Kraft, René Pollesch, Stefan Pucher, Annette Raffalt, Peter Raffalt, Carina Riedl, Roland Schimmelpfennig, Michael Thalheimer, Thomas Vinterberg, Alexander Wiegold, Sarantos Zervoulakos +Direktion Bergmann: Robert Borgmann, Jan Bosse, Barbara Frey, Dusan David Parizek, Felix Prader, Annette Raffalt, Georg Schmiedleitner, Christian Stückl +Andere Mitarbeiter[Bearbeiten] +Außer den Schauspielern arbeiten ungefähr 300 Burgtheater-Mitarbeiter am Gelingen der Theaterabende. Im Kollektivvertrag werden die Rechte und Pflichten der Theatermitarbeiter (natürlich auch die der Schauspieler) genau geregelt. Ein wichtiger Punkt ist, dass man nicht länger als bis 23 Uhr spielen darf, was natürlich bei längeren Vorstellungen ein Problem darstellen kann, so musste für die Aufführung des Sportstücks eine unüblich frühe Beginnzeit angesetzt werden. Es gibt etwa fünfzig Billeteure, die aber von einer anderen Firma angestellt sind. Als besonders wichtige Funktion gilt der Posten des Nachtfeuerwehrmannes. Für die Technische Gesamtleitung ist Johann Bugnar, seit der Spielzeit 2009/2010, zuständig. Als Technischer Leiter des Burgtheaters ist Ernst Meissl berufen worden; er ist der Nachfolger von Heinz Filar. Insgesamt (zusammen mit den Mitarbeitern der anderen Firmen, etwa der Kostümwerkstätten) unterstützen etwa 600 Leute die Arbeit an allen Spielstätten. + +Die Arbeit einer gut funktionierenden Komparserie ist für das Gelingen der Inszenierungen auch von großer Wichtigkeit. Beim Burgtheater arbeiten keine Statisten – die Laiendarsteller werden ausschließlich als Komparsen bezeichnet. Der Leiter der Komparserie ist seit 1986 Wolfgang Janich, der selbst eine Schauspielausbildung absolvierte und im Notfall auch einspringt.[39] In manchen Stücken tritt sogar der Chefinspizient, Klaus von Schwerin, der früher jahrelang an der Berliner Schaubühne arbeitete, als Komparse auf. Die Komparsen werden durch mehrstufige Castingverfahren sehr sorgfältig ausgewählt, und sogar die Begleiter der mitwirkenden Tiere werden Komparsen genannt und für die Betreuung der Tiere bezahlt. Claus Peymann wollte die Komparserie abschaffen und die Komparsenrollen mit Schauspielern besetzen, was diese allerdings verweigerten.[40] + +Anerkennung der schauspielerischen Leistung[Bearbeiten] +Anerkennung der Schauspieler im Ensemble[Bearbeiten] +Ensemblemitglied des Burgtheaters zu sein ist wohl der Traum für viele Schauspieler und gehört zu den Höhenpunkten der Karriere im Leben eines Künstlers auf der Bühne. Für besondere Leistungen werden die Ensemblemitglieder des Burgtheater noch zusätzlich geehrt. + +Eine Form der Ehrung ist der Burgtheater-Ring (der Concordia). Der Ring wurde von Jakob Lippowitz, dem Herausgeber des Neuen Wiener Journals, gestiftet und zwischen 1926 – dem Jahr des 150-jährigen Jubiläums der Burgtheater-Gründung – und 1934 jährlich an ein Mitglied des Burgtheaters oder an einen Bühnenautor für besondere Verdienste verliehen. Er wurde erstmals Arthur Schnitzler und Auguste Wilbrandt-Baudius zuerkannt und in den Folgejahren an die Dramatiker Hermann Bahr, Gerhart Hauptmann, Karl Schönherr, Ludwig Fulda sowie die Schauspieler Max Devrient, Georg Reimers, Hedwig Bleibtreu und Else Wohlgemuth verliehen. +Der Ehrenring des Burgtheaters wird seit 1. Oktober 1955 in unregelmäßigen Abständen von der Kollegenschaft des Burgtheaters an Ensemblemitglieder verliehen. Diese Auszeichnung wird vom Betriebsrat vorschlagen. +Ehrenmitglieder werden besonders verdiente Künstler seit 1922. Anlass war damals das vierzigjährige Bühnenjubiläum von Max Devrient. Zusammen mit ihm wurden Hugo Thimig, Georg Reimers sowie Auguste Wilbrandt-Baudius zu Ehrenmitgliedern ernannt. Die Ernennung erfolgte im Einverständnis mit der Bundestheaterverwaltung über Vorschlag der Burgtheater-Direktion. Diesen ersten Ernennungen folgten 1926, anlässlich des 150. Geburtstags des Burgtheaters, die offiziellen Richtlinien. Ihnen zufolge dürfen nur sehr prominente, verdienstvolle Ensemblemitglieder und auch diese erst nach langjähriger Zugehörigkeit zum Haus dieser Ehre teilhaftig werden. Die Zahl der lebenden Ehrenmitglieder sollte ein Zehntel des gesamten Mitgliederstandes nicht überschreiten. Der Titel darf in Wort oder Schrift nicht verwendet werden, wenn die Träger bei Veranstaltungen mitwirken, die mit der Würde des Titels unvereinbar wären, also wenn sie etwa in Operetten, Varietés oder Kabaretts auftreten. Die Namen der Ehrenmitglieder werden am Fuß der Feststiege auf der Volksgartenseite in Marmor gemeißelt und für die Ewigkeit festgehalten. Auch für das Begräbnis der Ehrenmitglieder gelten besondere Gepflogenheiten. Der Sarg des verstorbenen Schauspielers oder der verstorbenen Schauspielerin wird auf der Feststiege aufgebahrt und anschließend einmal rund um das Theater getragen. Den Ehrenmitgliedern wird seit dem 20. Oktober 2010 auch ein sog. Ehrenring der Direktion (nicht identisch mit dem Ehrenring des Burgtheaters, der vom Betriebsrat verliehen wird) überreicht (bis dahin wurde ihnen eine Urkunde überreicht). Der erste Träger des Ringes ist Michael Heltau. Der Ring wurde vom Juweilier Wagner entworfen und zeigt die Fassade des Burgtheaters. +Der Doyen (derzeit Michael Heltau) oder die Doyenne (seit 2015 Elisabeth Orth[41]) des Burgtheaters (von 2001 bis 2014 war dies Annemarie Düringer[42] und von 1987 bis 2000 Paula Wessely[43]) bleibt lebenslang mit der Bühne des Hauses verbunden, genießt also ein Engagement bis zum Tode, das heißt, er oder sie kann nicht in den Ruhestand versetzt werden. Diesen Ehrentitel bekommen zwei von den älteren Ehrenmitgliedern des Hauses – meistens sind das die dienstältesten, die schon am längsten Ensemblemitglieder sind –, jeweils eine Dame und ein Herr, die dann die Aufgabe haben, das Haus nach außen zu vertreten. Eine Voraussetzung für diese Auszeichnung ist, dass man zuvor zur Kammerschauspielerin beziehungsweise zum Kammerschauspieler ernannt worden sein muss. Die Auszeichnung wird erst nach dem Tod ihres Trägers weitergegeben. +Die Burgtheater-Galerie ist eine Sammlung von Künstlerporträts im Foyer, eine Art „Ehrengalerie“, die zum Teil noch aus dem alten Gebäude am Michaelerplatz stammt. Seit dem 23. Oktober 2006 zieren nicht nur alte Gemälde die Wände. Zeitgenössische Künstler porträtierten 2006 einige der heutigen Publikumslieblinge: Christy Astuy verewigte Annemarie Düringer und Branko Samarovski, Franz Graf zeichnete Elisabeth Orth und Ignaz Kirchner, die Fotografin Ilse Haider inszenierte fotografisch Andrea Clausen und Michael Heltau, Josef Kern malte Karlheinz Hackl und Martin Schwab, Klaus Maria Brandauer und Kirsten Dene wurden von Elke Krystufek porträtiert. Kitty Speiser und Gert Voss wurden in eigens dafür geschaffenen Rauminstallationen von Gregor Zivic dargestellt.[44] +Auf Anregung von Burg-Direktor Franz Herterich schuf Bundespräsident Michael Hainisch 1926 den Kammer-Titel für darstellende und ausübende Künstler auf dem Gebiet der Musik und darstellenden Kunst. Seit dieser Zeit gibt es in Österreich Kammerschauspieler und Kammersänger. Die ersten österreichischen Kammerschauspieler waren Maria Mayen, Maria Mayer, Raoul Aslan und Willi Thaller. Sie alle erhielten den Titel noch im Jubiläumsjahr 1926. In späteren Jahren blieb der Titel nicht mehr auf Mitglieder des Burgtheaters beschränkt, sondern wurde, wenngleich selten, auch an solche des Theaters in der Josefstadt und anderer österreichischer Bühnen vergeben. +Der Nestroy-Theaterpreis[Bearbeiten] + +Die Ausgezeichneten des Nestroy-Theaterpreises 2010, darunter Direktor Matthias Hartmann, auf der Bühne des Burgtheaters +Das Burgtheater (inkl. Akademietheater) ist mit seinen Produktionen seit 2000 das erfolgreichste Theater beim Nestroy-Theaterpreis. + +Nestroy-Theaterpreis 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 +Nominierungen/Siege 10/5 15/6 10/3 9/4 13/5 12/2 12/6 10/4 8/1 6/4 10/6 8/3 11/3 10/3 6/2 +Das Burgtheater im In- und Ausland[Bearbeiten] +Jedes Jahr gibt es Inszenierungen für die Salzburger Festspiele und für die Wiener Festwochen in Koproduktion mit dem Burgtheater, bei letzteren sind die Burg- und Akademietheater auch eine wichtige Spielstätte. Diese Produktionen werden in der Regel nach der Festspielzeit ins Repertoire aufgenommen. + +Produktionen des Burgtheaters werden regelmäßig zum Berliner Theatertreffen zu anderen internationalen Theaterfestivals eingeladen und die Burg wird auch im Ausland in Gastspielen gern gesehen, vor allem natürlich im deutschsprachigen Raum, aber auch in anderen Ländern. In den letzten Jahrzehnten gastierten Burg-Produktionen unter anderem in Amsterdam, Avignon, Berlin, Bogotá, Edinburgh, Meran, Moskau, Mülheim an der Ruhr, Prag, Venedig, Rom, Warschau und Zagreb. Erwähnenswert sind große Tourneen durch Japan und die Sowjetunion sowie Gastspiele in Israel und New York.[45] Ins Burgtheater werden auch oft Inszenierungen aus bedeutenden europäischen Häusern eingeladen, wie aus dem Thalia Theater in Hamburg. + +Das Burgtheater dient im Sommer als eine Spielstätte für das Tanzfestival ImPulsTanz, das mittlerweile als größtes europäisches Tanzereignis gilt. + +Von der Theaterzeitschrift Theater heute wurde das Burgtheater 2015 und 1995 zum Theater des Jahres gewählt.[46][47] + +Die Leitung des Burgtheaters[Bearbeiten] +Als Kaiser Joseph II. das Theater nächst der Burg zum Hof- und Nationaltheater erhob, schuf er jene Dreier-Konstruktion aus oberster Leitung, Verwaltung und künstlerischer Leitung, die im Wesentlichen bis heute erhalten geblieben ist. In der Monarchie lag die oberste Leitung in den Händen des Obersthofmeisteramtes oder des Oberstkämmereramtes. Die Verwaltung hatte wechselnde Titel, Theateroberdirektion oder Generalintendanz. Zudem war das Burgtheater einige Jahre lang verpachtet, wobei die Pächter es nur mit der obersten Instanz zu tun hatten, in Finanzverwaltung und Personalangelegenheiten aber selbständig waren. Für Stückauswahl und Spielpläne waren sie nur gegenüber der Zensur verantwortlich. Die künstlerische Leitung wiederum lag einmal in den Händen eines Regiekollegiums, dann wieder wurde sie einem artistischen Sekretär oder einem artistischen Direktor anvertraut, wurde aber auch interimistisch vom Generalintendanten oder von einem Schauspielerkollegium ausgeübt. + +Laut Gesetz vom 3. April 1919, dem sogenannten Habsburger-Gesetz, ging nach dem Ende der Monarchie das sogenannte hofärarische Vermögen des Hauses Habsburg-Lothringen in das Eigentum der Republik Österreich über. Dazu gehörten auch die Hoftheater, also das k. k. Hofburgtheater, die Hofoper sowie das Schönbrunner Schlosstheater. Dieses Gesetz wurde 1920 Teil der Bundesverfassung. + +Am 21. Mai 1920 unterstellte die österreichische Staatsregierung die „österreichischen Staatstheater“ (so die damalige offizielle Bezeichnung) dem Staatsamt für Inneres und Unterricht. Als Verwaltungsinstanz wurde die Staatstheaterverwaltung eingesetzt. Hier begann erneut eine Dreiteilung. Die oberste Leitung lag beim Unterrichtsminister, die Verwaltung bei der Staatstheaterverwaltung (später: Bundestheaterverwaltung; kurzzeitig auch: Generalintendanz; schließlich Bundestheaterverband; heute Bundestheater-Holding). Die künstlerische Leitung lag beim Direktor (mit unterschiedlich geregelten Befugnissen). + +Direktionen und künstlerische Leitungen des Burgtheaters[Bearbeiten] + +Heinrich Laube, 1849-1867 + +Franz von Dingelstedt, 1870-1881 + +Adolf von Wilbrandt, 1881-1887 + +Alfred von Berger, 1910-1912 + +Claus Peymann, 1986-1999 +→ Hauptartikel: Direktionen des Wiener Burgtheaters +Name Beginn Ende +Künstlerrepublik 1776 1789 +Johann Franz Brockmann 1790 1790 +Regiekollegium 1790 1794 +Peter von Braun 1794 1806 +Kavaliersdirektion 1807 1817 +Joseph Schreyvogel 1814 1832 +Johann Ludwig Deinhardstein 1832 1841 +Franz Ignaz von Holbein 1841 1849 +Heinrich Laube 1849 1867 +Eligius Freiherr von Münch-Bellinghausen; Pseudonym: Friedrich Halm 1867 1868 +August Wolff 1868 1870 +Franz Freiherr von Dingelstedt 1870 1881 +Adolf von Wilbrandt 1881 1887 +Adolf von Sonnenthal 1887 1888 +August Förster 1888 1889 +Adolf von Sonnenthal 1889 1890 +Max Burckhard 1890 1898 +Paul Schlenther 1898 1910 +Alfred Freiherr von Berger 1910 1912 +Hugo Thimig 1912 1917 +Max von Millenkovich 1917 1918 +Dreierkollegium 1918 1918 +Albert Heine 1918 1921 +Anton Wildgans 1921 1922 +Max Paulsen 1922 1923 +Franz Herterich 1923 1930 +Anton Wildgans 1930 1931 +Hermann Röbbeling 1932 1938 +Mirko Jelusich 1938 1938 +Ulrich Bettac 1938 1939 +Lothar Müthel 1939 1945 +Raoul Aslan 1945 1948 +Erhard Buschbeck 1948 1948 +Josef Gielen 1948 1954 +Adolf Rott 1954 1959 +Ernst Haeusserman 1959 1968 +Paul Hoffmann 1968 1971 +Gerhard Klingenberg 1971 1976 +Achim Benning 1976 1986 +Claus Peymann 1986 1999 +Klaus Bachler 1999 2009 +Matthias Hartmann 2009 2014 +Karin Bergmann 2014 2019 +Das Burgtheater in Film und Literatur[Bearbeiten] +Bis 1918 gab es ein Verbot, nach dem Schauspielern des Burgtheaters das Mitwirken in Filmen in jeder Form untersagt war. Das Kino galt als Bedrohung für den Fortbestand der Schauspielbühnen, und so wollte man den Filmproduzenten nicht in die Hand spielen. Eine Entspannung dieser Situation begann erst ab 1913 mit den Produktionen des Theaterintendanten Max Reinhardt. + +Siehe auch: Geschichte des österreichischen Stummfilms +1936 drehte Willi Forst den Spielfilm Burgtheater, der von einem alternden, sich noch einmal verliebenden Burgschauspieler – dargestellt von Werner Krauß – erzählt. Die Zeit der Handlung war 1897, die Personen – wie der „Burgdirektor“ Franz Herterich oder der Schauspieler Friedrich Mitterer, den Krauß verkörpert – waren fiktive Figuren, obwohl der Name Mitterer ein Anspielung auf den Namen des einst tatsächlich gefeierten Schauspielers Friedrich Mitterwurzer ist. Im Film werden Inszenierungen aus den letzten Jahren des 19. Jahrhunderts aufgegriffen, die es tatsächlich gab, Szenen aus Don Carlos, Faust und Kabale und Liebe werden nachgespielt.[48] + +Ab 1956 finanzierte das Unterrichtsministerium eine Reihe von Aufzeichnungen von Theaterstücken des Burgtheaters. Die Aufnahmen sollten im Kino gezeigt werden, weshalb mit Alfred Stöger ein Filmregisseur beauftragt wurde. Auf Filmmaterial wurden interessant besetzte Inszenierungen wie „Wilhelm Tell“ (1956, mit Ewald Balser als „Tell“ und Albin Skoda als „Gessler“), „Einen Jux will er sich machen“ (1957, mit Josef Meinrad und Inge Konradi), „Don Carlos“ (1960, mit Walther Reyer) und „Der Bauer als Millionär“ (1961, abermals mit Josef Meinrad) gebannt. Dennoch blieben die Kinoaufführungen spärlich besucht. Lediglich eine Generation von Schulkindern wurde damit zwangsbeglückt. + +1982 thematisierte Elfriede Jelinek in ihrem Stück Burgtheater die Zeit der NS-Diktatur in der Geschichte des Burgtheaters. Das Stück wurde 1982 in Bonn uraufgeführt sowie in Österreich im Grazer Theater am Bahnhof erstaufgeführt und stieß auf kontroverse Kritiken, weil es ein negatives Bild der damaligen legendären Ensemblemitglieder zeichnete, so von Paula Wessely und Attila Hörbiger, die in den Hauptfiguren klar erkennbar sind. + +Thomas Bernhard beschäftigte sich in seinen Werken immer wieder mit dem Thema Burgtheater, etwa in seinem Roman Holzfällen (1984) – dort lässt er einen saturierten Burgschauspieler auftreten – oder Alte Meister (1985), wo einzelne, zwischen Bewunderung und Verachtung pendelnde Bemerkungen dem Burgtheater gelten. Er schrieb drei Dramolette, in denen Claus Peymann persönlich vorkommt, Claus Peymann verlässt Bochum und geht als Burgtheaterdirektor nach Wien, Claus Peymann kauft sich eine Hose und geht mit mir essen und Claus Peymann und Hermann Beil auf der Sulzwiese, die 1990 erschienen. + +Heute dient das Burgtheater oft als beliebte Kulisse für Fernsehfilme. In der Krimikomödie Wiener Blut von Dirk Regel mit Ottfried Fischer in der Hauptrolle wird ein Burgschauspieler (dargestellt von Markus Hering) ermordet. Die letzten zwanzig Minuten des österreichischen Kinderfilms Die drei Posträuber (Regie: Andreas Prochaska), der 1998 nach einem Buch von Christine Nöstlinger gedreht wurde, spielen auf der Bühne und im Requisitenlager des Burgtheaters. + +Das Burgtheater im Fernsehen[Bearbeiten] +Die interessantesten Produktionen des Burgtheaters werden vom ORF aufgezeichnet und sind in dessen Programm, aber auch auf 3sat oder dem ZDFtheaterkanal zu sehen. Der Fernsehregisseur Peter Schönhofer macht statt bloßer Aufzeichnungen Theaterfilme der etwas anderen Art. Seine zwei bekanntesten sind die Verfilmungen von Don Carlos und von König Ottokars Glück und Ende. Die Dreharbeiten zu seinen Filmen dauern mehrere Tage und umfassen sowohl reguläre Aufführungen als auch Proben, bei denen die Kamerateams die Möglichkeit haben, Szenen direkt auf der Bühne zu drehen. Der Theaterfilm wird somit aus mehreren Vorstellungen zusammengeschnitten und beinhaltet auch Nahaufnahmen und auf der Bühne gefilmte Szenen, die bei herkömmlichen Live-Aufzeichnungen nicht machbar sind. Beim Berliner Theatertreffen 2005 wurde statt der Aufführung von Don Carlos der Theaterfilm von Schönhofer gezeigt, da kein Berliner Theater die technischen Voraussetzungen, die vom Burgtheater für die Inszenierung von Andrea Breth verlangt wurden, erfüllen konnte. Einige Produktionen sind auch auf DVD erhältlich, wenn das Stück nicht mehr gespielt wird. Durch Dokumentarfilme kann der Fernsehzuschauer ab und zu Einblick hinter die Kulissen gewinnen, wie im Film der ORF-Moderatorin Erna Cuesta (2005), Das Wiener Burgtheater – Vor und hinter den Kulissen einer Weltbühne. + +Publikationen[Bearbeiten] +Das Burgtheater hat ein Magazin, das vorspiel, das fünfmal jährlich erscheint. Es wird als Beilage der Tageszeitung Der Standard verbreitet, kann aber in den Spielstätten des Burgtheaters und in den größeren Theaterkassen gratis mitgenommen werden. Auf der Homepage findet man jedes vorspiel zum Herunterladen. Beim Deuticke Verlag erscheinen regelmäßig Bücher über wichtige Regisseure, Schauspieler und das Theater als „edition burgtheater“. Bis jetzt sind insgesamt acht Bände erschienen. \ No newline at end of file diff --git a/li.strolch.utils/src/test/resources/crypto_test_middle.txt b/li.strolch.utils/src/test/resources/crypto_test_middle.txt new file mode 100644 index 000000000..cf069255c --- /dev/null +++ b/li.strolch.utils/src/test/resources/crypto_test_middle.txt @@ -0,0 +1,3 @@ +Sodeli jetzt wöi mirs aber mau + + wüsse. © copyright \ No newline at end of file diff --git a/li.strolch.utils/src/test/resources/crypto_test_short.txt b/li.strolch.utils/src/test/resources/crypto_test_short.txt new file mode 100644 index 000000000..cf3e2e345 --- /dev/null +++ b/li.strolch.utils/src/test/resources/crypto_test_short.txt @@ -0,0 +1 @@ +Short \ No newline at end of file diff --git a/li.strolch.utils/src/test/resources/log4j.xml b/li.strolch.utils/src/test/resources/log4j.xml new file mode 100644 index 000000000..7a0499275 --- /dev/null +++ b/li.strolch.utils/src/test/resources/log4j.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/li.strolch.utils/src/test/resources/test.jks b/li.strolch.utils/src/test/resources/test.jks new file mode 100644 index 000000000..dfb55f343 Binary files /dev/null and b/li.strolch.utils/src/test/resources/test.jks differ diff --git a/li.strolch.utils/src/test/resources/test_data.csv b/li.strolch.utils/src/test/resources/test_data.csv new file mode 100644 index 000000000..d6b101a1e --- /dev/null +++ b/li.strolch.utils/src/test/resources/test_data.csv @@ -0,0 +1,6 @@ +#Comment +title;description;nrOfPages +A;a;1 +# Another comment +B;b;2 +C;c;3 diff --git a/li.strolch.website/pom.xml b/li.strolch.website/pom.xml index 7a975ffdd..6a4d4e23d 100644 --- a/li.strolch.website/pom.xml +++ b/li.strolch.website/pom.xml @@ -1,11 +1,12 @@ - + 4.0.0 li.strolch li.strolch - 1.1.0-SNAPSHOT + 1.2.0-SNAPSHOT ../pom.xml @@ -14,10 +15,4 @@ li.strolch.website Strolch's Website - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - diff --git a/li.strolch.xmlpers/.gitignore b/li.strolch.xmlpers/.gitignore new file mode 100644 index 000000000..0f44a0f25 --- /dev/null +++ b/li.strolch.xmlpers/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.classpath diff --git a/li.strolch.xmlpers/LICENSE b/li.strolch.xmlpers/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/li.strolch.xmlpers/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/li.strolch.xmlpers/README.md b/li.strolch.xmlpers/README.md new file mode 100644 index 000000000..051b06fc8 --- /dev/null +++ b/li.strolch.xmlpers/README.md @@ -0,0 +1,38 @@ +li.strolch.java.xmlpers +======================== + +[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=li.strolch.xmlpers)](http://jenkins.eitchnet.ch/view/li.strolch/job/li.strolch.xmlpers/) + +Generic Java XML persistence layer. Implemented to be light-weight and simple to use + +Dependencies +------------------------ +XmlPers is built by Maven3 and has very few external dependencies. The current dependencies are: +* the Java Runtime Environment 6 +* li.strolch.utils +* slf4j 1.7.2 +* slf4j-log4j bindings (only during tests) +* JUnit 4.10 (only during tests) + +Features +------------------------ +The idea behind XmlPers is to have a very lightweight database where each object is saved in its own XML file. + +The model for XmlPers is that for each persistable class the following information is available: +* Type (e.g. the class name) +* Optional Sub Type (e.g. some type in your class) +* Id + +This is not forced on the model itself, but in the DAO. Persisting changes is done by delegating to XmlFilePersister and the DAO must convert the object to a XML Document. + +See the tests for a reference implementation. + +Building +------------------------ +*Prerequisites: + * JDK 6 is installed and JAVA_HOME is properly set and ../bin is in path + * Maven 3 is installed and MAVEN_HOME is properly set and ../bin is in path + * li.strolch.utils is installed in your local Maven Repository +* Clone repository and change path to root +* Run maven: + * mvn clean install diff --git a/li.strolch.xmlpers/pom.xml b/li.strolch.xmlpers/pom.xml new file mode 100644 index 000000000..8f6e1aae2 --- /dev/null +++ b/li.strolch.xmlpers/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + li.strolch + li.strolch + 1.2.0-SNAPSHOT + ../pom.xml + + + li.strolch.xmlpers + jar + li.strolch.xmlpers + 2011 + + + + li.strolch + li.strolch.utils + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-site-plugin + + + + + diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/DomParser.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/DomParser.java new file mode 100644 index 000000000..1752cb209 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/DomParser.java @@ -0,0 +1,29 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import org.w3c.dom.Document; + +public interface DomParser { + + public T getObject(); + + public void setObject(T object); + + public Document toDom(); + + public void fromDom(Document document); +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileDao.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileDao.java new file mode 100644 index 000000000..0f744af14 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileDao.java @@ -0,0 +1,199 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.io.File; +import java.text.MessageFormat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.xmlpers.impl.PathBuilder; +import li.strolch.xmlpers.objref.ObjectRef; + +public class FileDao { + + private static final Logger logger = LoggerFactory.getLogger(FileDao.class); + + private final PersistenceTransaction tx; + private final boolean verbose; + private final PathBuilder pathBuilder; + + public FileDao(PersistenceTransaction tx, PathBuilder pathBuilder, boolean verbose) { + this.tx = tx; + this.pathBuilder = pathBuilder; + this.verbose = verbose; + } + + private void assertIsIdRef(IoOperation ioOperation, ObjectRef objectRef) { + if (!objectRef.isLeaf()) { + String msg = "A {0} operation can only be performed with IdRefs!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, ioOperation); + throw new XmlPersistenceException(msg); + } + } + + public boolean exists(PersistenceContext ctx) { + ObjectRef objectRef = ctx.getObjectRef(); + assertIsIdRef(IoOperation.READ, objectRef); + File path = objectRef.getPath(this.pathBuilder); + return path.exists(); + } + + public void performCreate(PersistenceContext ctx) { + ObjectRef objectRef = ctx.getObjectRef(); + assertIsIdRef(IoOperation.CREATE, objectRef); + File path = objectRef.getPath(this.pathBuilder); + logPath(IoOperation.CREATE, path, objectRef); + assertPathNotExists(path, objectRef); + createMissingParents(path, objectRef); + FileIo fileIo = new FileIo(path); + this.tx.getIoMode().write(ctx, fileIo); + } + + public void performRead(PersistenceContext ctx) { + ObjectRef objectRef = ctx.getObjectRef(); + assertIsIdRef(IoOperation.READ, objectRef); + File path = objectRef.getPath(this.pathBuilder); + if (!path.exists()) { + ctx.setObject(null); + return; + } + + logPath(IoOperation.READ, path, objectRef); + FileIo fileIo = new FileIo(path); + this.tx.getIoMode().read(ctx, fileIo); + } + + public void performUpdate(PersistenceContext ctx) { + ObjectRef objectRef = ctx.getObjectRef(); + assertIsIdRef(IoOperation.UPDATE, objectRef); + File path = objectRef.getPath(this.pathBuilder); + logPath(IoOperation.UPDATE, path, objectRef); + assertPathIsFileAndWritable(path, objectRef); + FileIo fileIo = new FileIo(path); + this.tx.getIoMode().write(ctx, fileIo); + } + + public void performDelete(PersistenceContext ctx) { + ObjectRef objectRef = ctx.getObjectRef(); + assertIsIdRef(IoOperation.DELETE, objectRef); + File path = objectRef.getPath(this.pathBuilder); + logPath(IoOperation.DELETE, path, objectRef); + assertPathIsFileAndWritable(path, objectRef); + if (!path.delete()) { + String msg = "Failed to delete file {0}"; //$NON-NLS-1$ + throw new RuntimeException(MessageFormat.format(msg, path.getAbsolutePath())); + } + + ObjectRef parentRef = objectRef.getParent(this.tx); + deleteEmptyDirectories(parentRef); + } + + private void deleteEmptyDirectories(ObjectRef objectRef) { + + // root can't be deleted + if (objectRef.isRoot()) + return; + + if (objectRef.isLeaf()) { + throw new IllegalArgumentException("IdRefs don't reference directories!"); //$NON-NLS-1$ + } + + objectRef.lock(); + + try { + + File directoryPath = objectRef.getPath(this.pathBuilder); + if (!directoryPath.isDirectory()) { + String msg = "The path for {0} is not a directory: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName(), directoryPath.getAbsolutePath()); + throw new IllegalArgumentException(msg); + } + + // stop if empty + if (directoryPath.list().length != 0) + return; + + // delete + if (!directoryPath.delete()) { + String msg = "Deletion of empty directory for {0} at {1} failed! Check file permissions!"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName(), directoryPath.getAbsolutePath()); + throw new XmlPersistenceException(msg); + } + + // log + if (this.verbose) { + String msg = "Deleted empty directory for {0} at {1}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, objectRef.getName(), directoryPath)); + } + + // recursively delete + ObjectRef parent = objectRef.getParent(this.tx); + deleteEmptyDirectories(parent); + + } finally { + objectRef.unlock(); + } + } + + private void logPath(IoOperation operation, File path, ObjectRef objectRef) { + if (this.verbose) { + String msg = "Path for operation {0} for {1} is at {2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, operation, objectRef.getName(), path.getAbsolutePath()); + logger.info(msg); + } + } + + private void createMissingParents(File path, ObjectRef objectRef) { + ObjectRef parentRef = objectRef.getParent(this.tx); + parentRef.lock(); + try { + File parentFile = parentRef.getPath(this.pathBuilder); + if (!parentFile.exists() && !parentFile.mkdirs()) { + String msg = "Could not create parent path for {0} at {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath()); + throw new XmlPersistenceException(msg); + } + } finally { + parentRef.unlock(); + } + } + + private void assertPathIsFileAndWritable(File path, ObjectRef objectRef) { + if (!path.exists()) { + String msg = "Persistence unit does not exist for {0} at {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath()); + throw new XmlPersistenceException(msg); + } + + if (!path.isFile() || !path.canWrite()) { + String msg; + msg = "Persistence unit is not a file or is not readable for {0} at {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath()); + throw new XmlPersistenceException(msg); + } + } + + private void assertPathNotExists(File path, ObjectRef objectRef) { + if (path.exists()) { + String msg = "Persistence unit already exists for {0} at {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath()); + throw new XmlPersistenceException(msg); + } + } + +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java new file mode 100644 index 000000000..81b15c357 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java @@ -0,0 +1,204 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.MessageFormat; + +import javanet.staxutils.IndentingXMLStreamWriter; +import li.strolch.utils.exceptions.XmlException; +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.helper.XmlHelper; +import li.strolch.xmlpers.util.DomUtil; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.FactoryConfigurationError; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +public class FileIo { + + public static final String DEFAULT_XML_VERSION = "1.0"; //$NON-NLS-1$ + public static final String DEFAULT_ENCODING = "utf-8"; //$NON-NLS-1$ + + private static final Logger logger = LoggerFactory.getLogger(FileIo.class); + + private final File path; + + public FileIo(File path) { + this.path = path; + } + + public void writeSax(PersistenceContext ctx) { + + XMLStreamWriter writer = null; + try { + try (FileWriter fileWriter = new FileWriter(this.path);) { + + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + writer = factory.createXMLStreamWriter(fileWriter); + writer = new IndentingXMLStreamWriter(writer); + + // start document + writer.writeStartDocument(DEFAULT_ENCODING, DEFAULT_XML_VERSION); + + // then delegate object writing to caller + SaxParser saxParser = ctx.getParserFactor().getSaxParser(); + saxParser.setObject(ctx.getObject()); + saxParser.write(writer); + + // and now end + writer.writeEndDocument(); + writer.flush(); + } + + } catch (FactoryConfigurationError | XMLStreamException | IOException e) { + if (this.path.exists()) + this.path.delete(); + String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, e.getMessage()); + throw new XmlException(msg, e); + } + + if (logger.isDebugEnabled()) { + String msg = "Wrote SAX to {0}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.path.getAbsolutePath())); + } + } + + public void readSax(PersistenceContext ctx) { + + try { + + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser sp = spf.newSAXParser(); + + SaxParser saxParser = ctx.getParserFactor().getSaxParser(); + DefaultHandler defaultHandler = saxParser.getDefaultHandler(); + sp.parse(this.path, defaultHandler); + + if (logger.isDebugEnabled()) { + String msg = "SAX parsed file {0}"; //$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.path.getAbsolutePath())); + } + + ctx.setObject(saxParser.getObject()); + + } catch (ParserConfigurationException | SAXException | IOException e) { + + String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$ + throw new XmlPersistenceException(MessageFormat.format(msg, e.getMessage()), e); + } + } + + public void writeDom(PersistenceContext ctx) { + + String lineSep = System.getProperty(XmlHelper.PROP_LINE_SEPARATOR); + + try { + + DomParser domParser = ctx.getParserFactor().getDomParser(); + domParser.setObject(ctx.getObject()); + Document document = domParser.toDom(); + String encoding = document.getInputEncoding(); + if (encoding == null || encoding.isEmpty()) { + // logger.info("No encoding passed. Using default encoding " + XmlHelper.DEFAULT_ENCODING); + encoding = XmlHelper.DEFAULT_ENCODING; + } + + if (!lineSep.equals(StringHelper.NEW_LINE)) { + logger.info("Overriding line separator to \\n"); //$NON-NLS-1$ + System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, StringHelper.NEW_LINE); + } + + // Set up a transformer + TransformerFactory transfac = TransformerFactory.newInstance(); + Transformer transformer = transfac.newTransformer(); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.ENCODING, encoding); + transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$ + // transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t"); + + // Transform to file + StreamResult result = new StreamResult(this.path); + Source xmlSource = new DOMSource(document); + transformer.transform(xmlSource, result); + + if (logger.isDebugEnabled()) { + String msg = MessageFormat.format("Wrote DOM to {0}", this.path.getAbsolutePath()); //$NON-NLS-1$ + logger.info(msg); + } + + } catch (TransformerFactoryConfigurationError | TransformerException e) { + + if (this.path.exists()) + this.path.delete(); + + String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, e.getMessage()); + throw new XmlException(msg, e); + + } finally { + System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, lineSep); + } + } + + public void readDom(PersistenceContext ctx) { + + try { + + DocumentBuilder docBuilder = DomUtil.createDocumentBuilder(); + Document document = docBuilder.parse(this.path); + DomParser domParser = ctx.getParserFactor().getDomParser(); + domParser.fromDom(document); + + if (logger.isDebugEnabled()) { + String msg = "DOM parsed file {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, this.path.getAbsolutePath()); + logger.info(msg); + } + + ctx.setObject(domParser.getObject()); + + } catch (SAXException | IOException e) { + String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, e.getMessage()); + throw new XmlPersistenceException(msg, e); + } + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/IoMode.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/IoMode.java new file mode 100644 index 000000000..e3b775da9 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/IoMode.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +/** + * @author Robert von Burg + * + */ +public enum IoMode { + + DOM { + @Override + public void write(PersistenceContext ctx, FileIo fileIo) { + fileIo.writeDom(ctx); + } + + @Override + public void read(PersistenceContext ctx, FileIo fileIo) { + fileIo.readDom(ctx); + } + }, + SAX { + @Override + public void write(PersistenceContext ctx, FileIo fileIo) { + fileIo.writeSax(ctx); + } + + @Override + public void read(PersistenceContext ctx, FileIo fileIo) { + fileIo.readSax(ctx); + } + }; + + /** + * @param ctx + * @param fileIo + */ + public void write(PersistenceContext ctx, FileIo fileIo) { + throw new UnsupportedOperationException("Override me!"); //$NON-NLS-1$ + } + + /** + * @param ctx + * @param fileIo + */ + public void read(PersistenceContext ctx, FileIo fileIo) { + throw new UnsupportedOperationException("Override me!"); //$NON-NLS-1$ + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/IoOperation.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/IoOperation.java new file mode 100644 index 000000000..cbbb147e0 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/IoOperation.java @@ -0,0 +1,21 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +public enum IoOperation { + + CREATE, READ, UPDATE, DELETE; +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/MetadataDao.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/MetadataDao.java new file mode 100644 index 000000000..49e0e79e1 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/MetadataDao.java @@ -0,0 +1,276 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.io.File; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.xmlpers.impl.PathBuilder; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.util.FilenameUtility; + +/** + * @author Robert von Burg + * + */ +public class MetadataDao { + + private static final Logger logger = LoggerFactory.getLogger(MetadataDao.class); + + private final PersistenceTransaction tx; + private final PathBuilder pathBuilder; + private final boolean verbose; + + public MetadataDao(PathBuilder pathBuilder, PersistenceTransaction tx, boolean verbose) { + this.tx = tx; + this.pathBuilder = pathBuilder; + this.verbose = verbose; + } + + public Set queryTypeSet(ObjectRef parentRef) { + assertNotClosed(this.tx); + assertNotIdRef(parentRef); + + parentRef.lock(); + try { + File queryPath = parentRef.getPath(this.pathBuilder); + Set keySet = queryTypeSet(queryPath); + + if (this.verbose) { + String msg = "Found {0} types for {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, keySet.size(), parentRef.getName()); + logger.info(msg); + } + + return keySet; + } finally { + parentRef.unlock(); + } + } + + public Set queryKeySet(ObjectRef parentRef) { + assertNotClosed(this.tx); + assertNotRootRef(parentRef); + assertNotIdRef(parentRef); + + parentRef.lock(); + try { + File queryPath = parentRef.getPath(this.pathBuilder); + Set keySet = queryKeySet(queryPath); + + if (this.verbose) { + String msg = "Found {0} objects for {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, keySet.size(), parentRef.getName()); + logger.info(msg); + } + + return keySet; + } finally { + parentRef.unlock(); + } + } + + public long queryTypeSize(ObjectRef parentRef) { + assertNotClosed(this.tx); + assertNotRootRef(parentRef); + assertNotIdRef(parentRef); + + parentRef.lock(); + try { + File queryPath = parentRef.getPath(this.pathBuilder); + long numberOfFiles = queryTypeSize(queryPath); + + if (this.verbose) { + String msg = "Found {0} types for {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, numberOfFiles, parentRef.getName()); + logger.info(msg); + } + + return numberOfFiles; + } finally { + parentRef.unlock(); + } + } + + public long querySize(ObjectRef parentRef) { + assertNotClosed(this.tx); + + parentRef.lock(); + try { + File queryPath = parentRef.getPath(this.pathBuilder); + long numberOfFiles = querySize(queryPath); + + if (this.verbose) { + String msg = "Found {0} objects for {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, numberOfFiles, parentRef.getName()); + logger.info(msg); + } + + return numberOfFiles; + } finally { + parentRef.unlock(); + } + } + + /** + * Returns the types, i.e. directories in the given query path + * + * @param queryPath + * the path for which the types should be gathered + * + * @return a set of types in the given query path + */ + private Set queryTypeSet(File queryPath) { + if (!queryPath.exists()) + return Collections.emptySet(); + + if (!queryPath.isDirectory()) { + String msg = "The path is not a directory, thus can not query type set for it: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, queryPath.getAbsolutePath()); + throw new IllegalArgumentException(msg); + } + + Set keySet = new HashSet<>(); + File[] subTypeFiles = queryPath.listFiles(); + for (File subTypeFile : subTypeFiles) { + if (subTypeFile.isDirectory()) { + String type = subTypeFile.getName(); + keySet.add(type); + } + } + + return keySet; + } + + /** + * Returns the ids of all objects in the given query path, i.e. the id part of all the files in the given query path + * + * @param queryPath + * the path for which the ids should be gathered + * + * @return a set of ids for the objects in the given query path + */ + private Set queryKeySet(File queryPath) { + if (!queryPath.exists()) + return Collections.emptySet(); + + if (!queryPath.isDirectory()) { + String msg = "The path is not a directory, thus can not query key set for it: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, queryPath.getAbsolutePath()); + throw new IllegalArgumentException(msg); + } + + Set keySet = new HashSet<>(); + + File[] subTypeFiles = queryPath.listFiles(); + for (File subTypeFile : subTypeFiles) { + if (subTypeFile.isFile()) { + String filename = subTypeFile.getName(); + String id = FilenameUtility.getId(filename); + keySet.add(id); + } + } + + return keySet; + } + + /** + * Returns the number of all types, i.e. directories in the given query path + * + * @param queryPath + * the path in which to count the types + * + * @return the number of types in the given query path + */ + private long queryTypeSize(File queryPath) { + if (!queryPath.exists()) + return 0L; + + if (!queryPath.isDirectory()) { + String msg = "The path is not a directory, thus can not query type size for it: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, queryPath.getAbsolutePath()); + throw new IllegalArgumentException(msg); + } + + long numberOfFiles = 0l; + + File[] subTypeFiles = queryPath.listFiles(); + for (File subTypeFile : subTypeFiles) { + + if (subTypeFile.isDirectory()) + numberOfFiles++; + } + return numberOfFiles; + } + + /** + * Returns the number of all objects in the given query path + * + * @param queryPath + * the path in which to count the objects + * + * @return the number of objects in the given query path + */ + private long querySize(File queryPath) { + if (!queryPath.exists()) + return 0L; + + if (!queryPath.isDirectory()) { + String msg = "The path is not a directory, thus can not query key size for it: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, queryPath.getAbsolutePath()); + throw new IllegalArgumentException(msg); + } + + long numberOfFiles = 0l; + + File[] subTypeFiles = queryPath.listFiles(); + for (File subTypeFile : subTypeFiles) { + + if (subTypeFile.isFile()) + numberOfFiles++; + } + return numberOfFiles; + } + + private void assertNotClosed(PersistenceTransaction tx) { + if (!tx.isOpen()) { + String msg = "Transaction has been closed and thus no operation can be performed!"; //$NON-NLS-1$ + throw new IllegalStateException(msg); + } + } + + private void assertNotIdRef(ObjectRef objectRef) { + if (objectRef.isLeaf()) { + String msg = "IdRef not allowed: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName()); + throw new IllegalArgumentException(msg); + } + } + + private void assertNotRootRef(ObjectRef objectRef) { + if (objectRef.isRoot()) { + String msg = "RootRef not allowed: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName()); + throw new IllegalArgumentException(msg); + } + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ModificationResult.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ModificationResult.java new file mode 100644 index 000000000..1b875a224 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ModificationResult.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.util.ArrayList; +import java.util.List; + +public class ModificationResult { + + private final String key; + private final List created; + private final List updated; + private final List deleted; + + public ModificationResult(String key) { + this.key = key; + this.created = new ArrayList<>(); + this.updated = new ArrayList<>(); + this.deleted = new ArrayList<>(); + } + + public ModificationResult(String key, List created, List updated, List deleted) { + this.key = key; + this.created = created; + this.updated = updated; + this.deleted = deleted; + } + + public String getKey() { + return this.key; + } + + @SuppressWarnings("unchecked") + public List getCreated() { + return (List) this.created; + } + + @SuppressWarnings("unchecked") + public List getUpdated() { + return (List) this.updated; + } + + @SuppressWarnings("unchecked") + public List getDeleted() { + return (List) this.deleted; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ObjectDao.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ObjectDao.java new file mode 100644 index 000000000..03d9a3436 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ObjectDao.java @@ -0,0 +1,305 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import static li.strolch.xmlpers.util.AssertionUtil.assertIsIdRef; +import static li.strolch.xmlpers.util.AssertionUtil.assertIsNotIdRef; +import static li.strolch.xmlpers.util.AssertionUtil.assertIsNotRootRef; +import static li.strolch.xmlpers.util.AssertionUtil.assertNotNull; +import static li.strolch.xmlpers.util.AssertionUtil.assertObjectRead; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import li.strolch.utils.objectfilter.ObjectFilter; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.SubTypeRef; +import li.strolch.xmlpers.objref.TypeRef; + +/** + * @author Robert von Burg + * + */ +public class ObjectDao { + + private final ObjectFilter objectFilter; + private final FileDao fileDao; + private final PersistenceTransaction tx; + private PersistenceContextFactoryDelegator ctxFactoryDelegator; + + public ObjectDao(PersistenceTransaction tx, FileDao fileDao, ObjectFilter objectFilter) { + this.tx = tx; + this.fileDao = fileDao; + this.objectFilter = objectFilter; + this.ctxFactoryDelegator = this.tx.getRealm().getCtxFactoryDelegator(); + } + + public void add(T object) { + assertNotClosed(); + assertNotNull(object); + PersistenceContext ctx = createCtx(object); + ctx.getObjectRef().lock(); + this.objectFilter.add(ctx.getObjectRef().getType(), ctx); + } + + public void addAll(List objects) { + assertNotClosed(); + assertNotNull(objects); + if (!objects.isEmpty()) { + for (T object : objects) { + PersistenceContext ctx = createCtx(object); + ctx.getObjectRef().lock(); + this.objectFilter.add(ctx.getObjectRef().getType(), ctx); + } + } + } + + public void update(T object) { + assertNotClosed(); + assertNotNull(object); + PersistenceContext ctx = createCtx(object); + ctx.getObjectRef().lock(); + this.objectFilter.update(ctx.getObjectRef().getType(), ctx); + } + + public void updateAll(List objects) { + assertNotClosed(); + assertNotNull(objects); + if (!objects.isEmpty()) { + for (T object : objects) { + PersistenceContext ctx = createCtx(object); + ctx.getObjectRef().lock(); + this.objectFilter.update(ctx.getObjectRef().getType(), ctx); + } + } + } + + public void remove(T object) { + assertNotClosed(); + assertNotNull(object); + PersistenceContext ctx = createCtx(object); + ctx.getObjectRef().lock(); + this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); + } + + public void removeAll(List objects) { + assertNotClosed(); + assertNotNull(objects); + if (!objects.isEmpty()) { + for (T object : objects) { + PersistenceContext ctx = createCtx(object); + ctx.getObjectRef().lock(); + this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); + } + } + } + + public long removeAllBy(TypeRef typeRef) { + assertNotClosed(); + + long removed = 0; + + Set refs = new HashSet<>(); + typeRef.lock(); + refs.add(typeRef); + try { + + Set types = this.tx.getMetadataDao().queryTypeSet(typeRef); + for (String type : types) { + ObjectRef childTypeRef = typeRef.getChildTypeRef(this.tx, type); + childTypeRef.lock(); + refs.add(childTypeRef); + + Set ids = queryKeySet(childTypeRef); + for (String id : ids) { + + ObjectRef idRef = childTypeRef.getChildIdRef(this.tx, id); + + PersistenceContext ctx = createCtx(idRef); + ctx.getObjectRef().lock(); + this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); + removed++; + } + } + } finally { + for (ObjectRef ref : refs) { + ref.unlock(); + } + } + + return removed; + } + + public long removeAllBy(SubTypeRef subTypeRef) { + assertNotClosed(); + assertIsNotRootRef(subTypeRef); + assertIsNotIdRef(subTypeRef); + + long removed = 0; + + subTypeRef.lock(); + try { + Set ids = queryKeySet(subTypeRef); + for (String id : ids) { + + ObjectRef idRef = subTypeRef.getChildIdRef(this.tx, id); + + PersistenceContext ctx = createCtx(idRef); + ctx.getObjectRef().lock(); + this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); + removed++; + } + } finally { + subTypeRef.unlock(); + } + + return removed; + } + + public void removeById(ObjectRef objectRef) { + assertNotClosed(); + assertIsIdRef(objectRef); + PersistenceContext ctx = createCtx(objectRef); + ctx.getObjectRef().lock(); + this.objectFilter.remove(objectRef.getType(), ctx); + } + + public void removeAll(ObjectRef parentRef) { + assertNotClosed(); + assertIsNotIdRef(parentRef); + assertIsNotRootRef(parentRef); + + parentRef.lock(); + try { + + Set keySet = queryKeySet(parentRef); + for (String id : keySet) { + + ObjectRef childRef = parentRef.getChildIdRef(this.tx, id); + PersistenceContext ctx = createCtx(childRef); + ctx.getObjectRef().lock(); + this.objectFilter.remove(childRef.getType(), ctx); + } + } finally { + parentRef.unlock(); + } + } + + public boolean hasElement(ObjectRef objectRef) { + assertNotClosed(); + assertIsIdRef(objectRef); + + objectRef.lock(); + try { + PersistenceContext ctx = objectRef. createPersistenceContext(this.tx); + return this.fileDao.exists(ctx); + } finally { + objectRef.unlock(); + } + } + + public T queryById(ObjectRef objectRef) { + assertNotClosed(); + assertIsIdRef(objectRef); + + objectRef.lock(); + try { + PersistenceContext ctx = objectRef. createPersistenceContext(this.tx); + this.fileDao.performRead(ctx); + return ctx.getObject(); + } finally { + objectRef.unlock(); + } + } + + public List queryAll(ObjectRef parentRef) { + assertNotClosed(); + assertIsNotIdRef(parentRef); + + parentRef.lock(); + try { + + MetadataDao metadataDao = this.tx.getMetadataDao(); + Set keySet = metadataDao.queryKeySet(parentRef); + + List result = new ArrayList<>(); + for (String id : keySet) { + + ObjectRef childRef = parentRef.getChildIdRef(this.tx, id); + PersistenceContext childCtx = childRef.createPersistenceContext(this.tx); + childCtx.getObjectRef().lock(); + try { + this.fileDao.performRead(childCtx); + assertObjectRead(childCtx); + result.add(childCtx.getObject()); + } finally { + childCtx.getObjectRef().unlock(); + } + } + + return result; + + } finally { + parentRef.unlock(); + } + } + + public Set queryKeySet(ObjectRef parentRef) { + assertNotClosed(); + assertIsNotIdRef(parentRef); + + parentRef.lock(); + try { + MetadataDao metadataDao = this.tx.getMetadataDao(); + Set keySet = metadataDao.queryKeySet(parentRef); + return keySet; + } finally { + parentRef.unlock(); + } + } + + public long querySize(ObjectRef parentRef) { + assertNotClosed(); + assertIsNotIdRef(parentRef); + + parentRef.lock(); + try { + MetadataDao metadataDao = this.tx.getMetadataDao(); + long size = metadataDao.querySize(parentRef); + return size; + } finally { + parentRef.unlock(); + } + } + + public PersistenceContext createCtx(T object) { + return this.ctxFactoryDelegator. getCtxFactory(object.getClass()).createCtx(this.tx.getObjectRefCache(), + object); + } + + public PersistenceContext createCtx(ObjectRef objectRef) { + String type = objectRef.getType(); + PersistenceContextFactory ctxFactory = this.ctxFactoryDelegator. getCtxFactory(type); + return ctxFactory.createCtx(objectRef); + } + + private void assertNotClosed() { + if (!this.tx.isOpen()) + throw new IllegalStateException("Transaction has been closed and thus no operation can be performed!"); //$NON-NLS-1$ + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ParserFactory.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ParserFactory.java new file mode 100644 index 000000000..e6a02d551 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/ParserFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +public interface ParserFactory { + + public DomParser getDomParser(); + + public SaxParser getSaxParser(); +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceConstants.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceConstants.java new file mode 100644 index 000000000..9f5d6224c --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceConstants.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +/** + * @author Robert von Burg + * + */ +@SuppressWarnings("nls") +public class PersistenceConstants { + + private static final String PROP_PREFIX = "li.strolch.xmlpers."; + public static final String PROP_VERBOSE = PROP_PREFIX + "verbose"; + public static final String PROP_BASEPATH = PROP_PREFIX + "basePath"; + public static final String PROP_DAO_FACTORY_CLASS = PROP_PREFIX + "daoFactoryClass"; + public static final String PROP_XML_IO_MOD = PROP_PREFIX + "ioMode"; + public static final String PROP_LOCK_TIME_MILLIS = PROP_PREFIX + "lockTimeSeconds"; +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContext.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContext.java new file mode 100644 index 000000000..3963e52e3 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContext.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import li.strolch.xmlpers.objref.ObjectRef; + +public class PersistenceContext { + + private final ObjectRef objectRef; + private T object; + private ParserFactory parserFactory; + + public PersistenceContext(ObjectRef objectRef) { + this.objectRef = objectRef; + } + + public ObjectRef getObjectRef() { + return this.objectRef; + } + + public T getObject() { + return this.object; + } + + public void setObject(T object) { + this.object = object; + } + + public ParserFactory getParserFactor() { + return this.parserFactory; + } + + public void setParserFactory(ParserFactory parserFactory) { + this.parserFactory = parserFactory; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.objectRef == null) ? 0 : this.objectRef.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PersistenceContext other = (PersistenceContext) obj; + if (this.objectRef == null) { + if (other.objectRef != null) + return false; + } else if (!this.objectRef.equals(other.objectRef)) + return false; + return true; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PersistenceContext [objectRef="); + builder.append(this.objectRef); + builder.append(", object="); + builder.append(this.object); + builder.append(", parserFactory="); + builder.append(this.parserFactory); + builder.append("]"); + return builder.toString(); + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContextFactory.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContextFactory.java new file mode 100644 index 000000000..44a485ae9 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContextFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; + +public interface PersistenceContextFactory { + + public PersistenceContext createCtx(ObjectRef objectRef); + + public PersistenceContext createCtx(ObjectReferenceCache objectRefCache, T t); + +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContextFactoryDelegator.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContextFactoryDelegator.java new file mode 100644 index 000000000..ae721d5f6 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceContextFactoryDelegator.java @@ -0,0 +1,68 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Robert von Burg + * + */ +public class PersistenceContextFactoryDelegator { + + private Map> contextFactoryCacheByType; + private Map, PersistenceContextFactory> contextFactoryCacheByClass; + + public PersistenceContextFactoryDelegator() { + this.contextFactoryCacheByType = new HashMap<>(); + this.contextFactoryCacheByClass = new HashMap<>(); + } + + public void registerPersistenceContextFactory(Class classType, String type, + PersistenceContextFactory ctxFactory) { + + this.contextFactoryCacheByClass.put(classType, ctxFactory); + this.contextFactoryCacheByType.put(type, ctxFactory); + } + + public PersistenceContextFactory getCtxFactory(Class classType) { + + @SuppressWarnings("unchecked") + PersistenceContextFactory ctxFactory = (PersistenceContextFactory) this.contextFactoryCacheByClass + .get(classType); + if (ctxFactory != null) + return ctxFactory; + + String msg = "No context factory is registered for {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, classType); + throw new IllegalArgumentException(msg); + } + + public PersistenceContextFactory getCtxFactory(String type) { + + @SuppressWarnings("unchecked") + PersistenceContextFactory ctxFactory = (PersistenceContextFactory) this.contextFactoryCacheByType + .get(type); + if (ctxFactory != null) + return ctxFactory; + + String msg = "No context factory is registered for type {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, type); + throw new IllegalArgumentException(msg); + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceManager.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceManager.java new file mode 100644 index 000000000..0a10cea56 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceManager.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +/** + * @author Robert von Burg + * + */ +public interface PersistenceManager { + + public static final String DEFAULT_REALM = "defaultRealm"; //$NON-NLS-1$ + + public PersistenceContextFactoryDelegator getCtxFactory(); + + public PersistenceTransaction openTx(); + + public PersistenceTransaction openTx(String realm); +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceManagerLoader.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceManagerLoader.java new file mode 100644 index 000000000..ab3d50c70 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceManagerLoader.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.util.Properties; + +import li.strolch.xmlpers.impl.DefaultPersistenceManager; + +/** + * @author Robert von Burg + * + */ +public class PersistenceManagerLoader { + + public static PersistenceManager load(Properties properties) { + + DefaultPersistenceManager persistenceManager = new DefaultPersistenceManager(); + persistenceManager.initialize(properties); + return persistenceManager; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceRealm.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceRealm.java new file mode 100644 index 000000000..bf54f27ec --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceRealm.java @@ -0,0 +1,39 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import li.strolch.xmlpers.objref.ObjectReferenceCache; + +public interface PersistenceRealm { + + /** + * @return the realm + */ + public abstract String getRealmName(); + + public abstract PersistenceContextFactoryDelegator getCtxFactoryDelegator(); + + /** + * @return the objectRefCache + */ + public abstract ObjectReferenceCache getObjectRefCache(); + + /** + * @return the persistenceManager + */ + public abstract PersistenceManager getPersistenceManager(); + +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceTransaction.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceTransaction.java new file mode 100644 index 000000000..3cd9ec0c2 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/PersistenceTransaction.java @@ -0,0 +1,66 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import li.strolch.xmlpers.objref.ObjectReferenceCache; + +/** + * @author Robert von Burg + * + */ +public interface PersistenceTransaction extends AutoCloseable { + + /** + * Returns the {@link TransactionResult} for this transaction + * + * @return the {@link TransactionResult} + * + * @throws IllegalStateException + * if the transaction has not yet been closed + */ + public TransactionResult getTransactionResult() throws IllegalStateException; + + /** + * @throws IllegalStateException + * if a result is already set + */ + public void setTransactionResult(TransactionResult txResult) throws IllegalStateException; + + public void setCloseStrategy(TransactionCloseStrategy closeStrategy); + + public void autoCloseableCommit(); + + public void autoCloseableRollback(); + + @Override + public void close() throws XmlPersistenceException; + + public boolean isOpen(); + + public ObjectDao getObjectDao(); + + public MetadataDao getMetadataDao(); + + public FileDao getFileDao(); + + public ObjectReferenceCache getObjectRefCache(); + + public PersistenceRealm getRealm(); + + public IoMode getIoMode(); + + public void setIoMode(IoMode ioMode); +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/SaxParser.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/SaxParser.java new file mode 100644 index 000000000..a51d2b715 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/SaxParser.java @@ -0,0 +1,32 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.xml.sax.helpers.DefaultHandler; + +public interface SaxParser { + + public T getObject(); + + public void setObject(T object); + + public DefaultHandler getDefaultHandler(); + + public void write(XMLStreamWriter xmlWriter) throws XMLStreamException; +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionCloseStrategy.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionCloseStrategy.java new file mode 100644 index 000000000..b35eb80fd --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionCloseStrategy.java @@ -0,0 +1,39 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +public enum TransactionCloseStrategy { + COMMIT() { + @Override + public void close(PersistenceTransaction tx) { + tx.autoCloseableCommit(); + } + }, + + ROLLBACK() { + @Override + public void close(PersistenceTransaction tx) { + tx.autoCloseableRollback(); + } + }; + + /** + * @param tx + */ + public void close(PersistenceTransaction tx) { + throw new UnsupportedOperationException("Override in enum!"); //$NON-NLS-1$ + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionResult.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionResult.java new file mode 100644 index 000000000..bc5f2cae4 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionResult.java @@ -0,0 +1,218 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import li.strolch.utils.helper.StringHelper; + +public class TransactionResult { + + private String realm; + private TransactionState state; + private Exception failCause; + + private Date startTime; + private long txDuration; + private long closeDuration; + + private Map modificationByKey; + + public TransactionResult() { + this.state = TransactionState.OPEN; + this.modificationByKey = new HashMap<>(); + } + + /** + * @return the realm + */ + public String getRealm() { + return this.realm; + } + + /** + * @param realm + * the realm to set + */ + public void setRealm(String realm) { + this.realm = realm; + } + + /** + * @return the state + */ + public TransactionState getState() { + return this.state; + } + + /** + * @param state + * the state to set + */ + public void setState(TransactionState state) { + this.state = state; + } + + /** + * The internal exception why the transaction failed + * + * @return the failCause + */ + public Exception getFailCause() { + return this.failCause; + } + + /** + * @param failCause + * the failCause to set + */ + public void setFailCause(Exception failCause) { + this.failCause = failCause; + } + + /** + * Start time of the transaction + * + * @return the startTime + */ + public Date getStartTime() { + return this.startTime; + } + + /** + * @param startTime + * the startTime to set + */ + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + /** + * The duration the transaction was open in nanoseconds + * + * @return the txDuration + */ + public long getTxDuration() { + return this.txDuration; + } + + /** + * @param txDuration + * the txDuration to set + */ + public void setTxDuration(long txDuration) { + this.txDuration = txDuration; + } + + /** + * The duration the transaction took to close in nanoseconds + * + * @return the closeDuration + */ + public long getCloseDuration() { + return this.closeDuration; + } + + /** + * @param closeDuration + * the closeDuration to set + */ + public void setCloseDuration(long closeDuration) { + this.closeDuration = closeDuration; + } + + /** + * @param modificationByKey + * the modificationByKey to set + */ + public void setModificationByKey(Map modificationByKey) { + this.modificationByKey = modificationByKey; + } + + /** + * @return + */ + public Set getKeys() { + return this.modificationByKey.keySet(); + } + + /** + * @param key + * @return + */ + public ModificationResult getModificationResult(String key) { + return this.modificationByKey.get(key); + } + + @SuppressWarnings("nls") + public String getLogMessage() { + + int nrOfObjects = 0; + for (ModificationResult result : this.modificationByKey.values()) { + nrOfObjects += result.getCreated().size(); + nrOfObjects += result.getUpdated().size(); + nrOfObjects += result.getDeleted().size(); + } + + StringBuilder sb = new StringBuilder(); + sb.append("TX for realm "); + sb.append(getRealm()); + switch (this.state) { + case OPEN: + sb.append(" is still open after "); + break; + case COMMITTED: + sb.append(" was completed after "); + break; + case ROLLED_BACK: + sb.append(" was rolled back after "); + break; + case FAILED: + sb.append(" has failed after "); + break; + default: + sb.append(" is in unhandled state "); + sb.append(this.state); + sb.append(" after "); + } + + sb.append(StringHelper.formatNanoDuration(this.txDuration)); + sb.append(" with close operation taking "); + sb.append(StringHelper.formatNanoDuration(this.closeDuration)); + sb.append(". "); + sb.append(nrOfObjects); + sb.append(" objects in "); + sb.append(this.modificationByKey.size()); + sb.append(" types were modified."); + + return sb.toString(); + } + + /** + * Clears all fields of this result, allowing it to be reused + */ + public void clear() { + this.realm = null; + this.state = null; + this.failCause = null; + this.startTime = null; + this.txDuration = 0L; + this.closeDuration = 0L; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionState.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionState.java new file mode 100644 index 000000000..f0a62334e --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/TransactionState.java @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +public enum TransactionState { + OPEN, // + COMMITTED, // + ROLLED_BACK, // + FAILED; +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/XmlPersistenceException.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/XmlPersistenceException.java new file mode 100644 index 000000000..c57604208 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/XmlPersistenceException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.api; + +/** + * @author Robert von Burg + */ +public class XmlPersistenceException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * @param message + * @param cause + */ + public XmlPersistenceException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + */ + public XmlPersistenceException(String message) { + super(message); + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceManager.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceManager.java new file mode 100644 index 000000000..bf57b6808 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceManager.java @@ -0,0 +1,131 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.impl; + +import java.io.File; +import java.lang.reflect.Field; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.PropertiesHelper; +import li.strolch.utils.helper.StringHelper; +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceContextFactoryDelegator; +import li.strolch.xmlpers.api.PersistenceManager; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.api.XmlPersistenceException; +import li.strolch.xmlpers.objref.LockableObject; +import li.strolch.xmlpers.objref.ObjectReferenceCache; + +/** + * @author Robert von Burg + * + */ +public class DefaultPersistenceManager implements PersistenceManager { + + protected static final Logger logger = LoggerFactory.getLogger(DefaultPersistenceManager.class); + + protected boolean initialized; + protected boolean verbose; + protected IoMode defaultIoMode; + protected Properties properties; + protected Map realmMap; + private PersistenceContextFactoryDelegator ctxFactory; + + public void initialize(Properties properties) { + if (this.initialized) + throw new IllegalStateException("Already initialized!"); //$NON-NLS-1$ + + String context = DefaultPersistenceManager.class.getSimpleName(); + + // get properties + boolean verbose = PropertiesHelper.getPropertyBool(properties, context, PersistenceConstants.PROP_VERBOSE, + Boolean.FALSE).booleanValue(); + String ioModeS = PropertiesHelper.getProperty(properties, context, PersistenceConstants.PROP_XML_IO_MOD, + IoMode.DOM.name()); + IoMode ioMode = IoMode.valueOf(ioModeS); + long lockTime = PropertiesHelper.getPropertyLong(properties, context, + PersistenceConstants.PROP_LOCK_TIME_MILLIS, 10000L); + + // set lock time on LockableObject + try { + Field lockTimeField = LockableObject.class.getDeclaredField("tryLockTime");//$NON-NLS-1$ + lockTimeField.setAccessible(true); + lockTimeField.setLong(null, lockTime); + logger.info("Using a max lock acquire time of " + StringHelper.formatMillisecondsDuration(lockTime)); //$NON-NLS-1$ + } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException("Failed to configure tryLockTime on LockableObject!", e); //$NON-NLS-1$ + } + + // validate base path + validateBasePath(properties); + + this.properties = properties; + this.verbose = verbose; + this.defaultIoMode = ioMode; + this.realmMap = new HashMap<>(); + this.ctxFactory = new PersistenceContextFactoryDelegator(); + } + + private void validateBasePath(Properties properties) { + String context = DefaultPersistenceManager.class.getSimpleName(); + String basePath = PropertiesHelper.getProperty(properties, context, PersistenceConstants.PROP_BASEPATH, null); + + // validate base path exists and is writable + File basePathF = new File(basePath); + if (!basePathF.exists()) + throw new XmlPersistenceException(MessageFormat.format("The database store path does not exist at {0}", //$NON-NLS-1$ + basePathF.getAbsolutePath())); + if (!basePathF.canWrite()) + throw new XmlPersistenceException(MessageFormat.format("The database store path is not writeable at {0}", //$NON-NLS-1$ + basePathF.getAbsolutePath())); + } + + @Override + public PersistenceContextFactoryDelegator getCtxFactory() { + return this.ctxFactory; + } + + @Override + public PersistenceTransaction openTx() { + return openTx(DEFAULT_REALM); + } + + @Override + public synchronized PersistenceTransaction openTx(String realmName) { + + DefaultPersistenceRealm persistenceRealm = this.realmMap.get(realmName); + if (persistenceRealm == null) { + + PathBuilder pathBuilder = new PathBuilder(realmName, this.properties); + ObjectReferenceCache objectRefCache = new ObjectReferenceCache(realmName); + persistenceRealm = new DefaultPersistenceRealm(realmName, this, this.ctxFactory, pathBuilder, + objectRefCache); + + this.realmMap.put(realmName, persistenceRealm); + } + + PersistenceTransaction tx = new DefaultPersistenceTransaction(persistenceRealm, this.verbose); + tx.setIoMode(this.defaultIoMode); + return tx; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceRealm.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceRealm.java new file mode 100644 index 000000000..33046f9d7 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceRealm.java @@ -0,0 +1,74 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.impl; + +import li.strolch.xmlpers.api.PersistenceContextFactoryDelegator; +import li.strolch.xmlpers.api.PersistenceManager; +import li.strolch.xmlpers.api.PersistenceRealm; +import li.strolch.xmlpers.objref.ObjectReferenceCache; + +public class DefaultPersistenceRealm implements PersistenceRealm { + private final PersistenceManager persistenceManager; + private final PersistenceContextFactoryDelegator ctxFactory; + private final String realmName; + private final ObjectReferenceCache objectRefCache; + private final PathBuilder pathBuilder; + + public DefaultPersistenceRealm(String realm, PersistenceManager persistenceManager, + PersistenceContextFactoryDelegator ctxFactory, PathBuilder pathBuilder, ObjectReferenceCache objectRefCache) { + this.ctxFactory = ctxFactory; + this.pathBuilder = pathBuilder; + this.realmName = realm; + this.persistenceManager = persistenceManager; + this.objectRefCache = objectRefCache; + } + + /** + * @return the realm + */ + @Override + public String getRealmName() { + return this.realmName; + } + + @Override + public PersistenceContextFactoryDelegator getCtxFactoryDelegator() { + return this.ctxFactory; + } + + /** + * @return the objectRefCache + */ + @Override + public ObjectReferenceCache getObjectRefCache() { + return this.objectRefCache; + } + + /** + * @return the persistenceManager + */ + @Override + public PersistenceManager getPersistenceManager() { + return this.persistenceManager; + } + + /** + * @return the pathBuilder + */ + PathBuilder getPathBuilder() { + return this.pathBuilder; + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceTransaction.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceTransaction.java new file mode 100644 index 000000000..14160e6ab --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/DefaultPersistenceTransaction.java @@ -0,0 +1,324 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.impl; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.objectfilter.ObjectFilter; +import li.strolch.xmlpers.api.FileDao; +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.MetadataDao; +import li.strolch.xmlpers.api.ModificationResult; +import li.strolch.xmlpers.api.ObjectDao; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceRealm; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.api.TransactionCloseStrategy; +import li.strolch.xmlpers.api.TransactionResult; +import li.strolch.xmlpers.api.TransactionState; +import li.strolch.xmlpers.api.XmlPersistenceException; +import li.strolch.xmlpers.objref.ObjectReferenceCache; + +/** + * @author Robert von Burg + * + */ +public class DefaultPersistenceTransaction implements PersistenceTransaction { + + private static final Logger logger = LoggerFactory.getLogger(DefaultPersistenceTransaction.class); + + private final DefaultPersistenceRealm realm; + private final boolean verbose; + + private final ObjectFilter objectFilter; + private final ObjectDao objectDao; + private final MetadataDao metadataDao; + + private FileDao fileDao; + private IoMode ioMode; + + private TransactionCloseStrategy closeStrategy; + + private TransactionState state; + private long startTime; + private Date startTimeDate; + private TransactionResult txResult; + + public DefaultPersistenceTransaction(DefaultPersistenceRealm realm, boolean verbose) { + this.startTime = System.nanoTime(); + this.startTimeDate = new Date(); + this.realm = realm; + this.verbose = verbose; + this.objectFilter = new ObjectFilter(); + this.fileDao = new FileDao(this, realm.getPathBuilder(), verbose); + this.objectDao = new ObjectDao(this, this.fileDao, this.objectFilter); + this.metadataDao = new MetadataDao(realm.getPathBuilder(), this, verbose); + + this.closeStrategy = TransactionCloseStrategy.COMMIT; + this.state = TransactionState.OPEN; + } + + @Override + public void setTransactionResult(TransactionResult txResult) throws IllegalStateException { + if (this.txResult != null) { + String msg = "The transaction already has a result set!"; //$NON-NLS-1$ + throw new IllegalStateException(msg); + } + this.txResult = txResult; + } + + @Override + public TransactionResult getTransactionResult() throws IllegalStateException { + if (isOpen()) { + String msg = "The transaction is still open thus has no result yet! Either commit or rollback before calling this method"; //$NON-NLS-1$ + throw new IllegalStateException(msg); + } + return this.txResult; + } + + @Override + public PersistenceRealm getRealm() { + return this.realm; + } + + @Override + public ObjectDao getObjectDao() { + return this.objectDao; + } + + @Override + public MetadataDao getMetadataDao() { + return this.metadataDao; + } + + @Override + public FileDao getFileDao() { + return this.fileDao; + } + + @Override + public ObjectReferenceCache getObjectRefCache() { + return this.realm.getObjectRefCache(); + } + + @Override + public void setCloseStrategy(TransactionCloseStrategy closeStrategy) { + this.closeStrategy = closeStrategy; + } + + @Override + public void close() throws XmlPersistenceException { + this.closeStrategy.close(this); + } + + @Override + public void autoCloseableRollback() { + long start = System.nanoTime(); + if (this.state == TransactionState.COMMITTED) + throw new IllegalStateException("Transaction has already been committed!"); //$NON-NLS-1$ + + if (this.state != TransactionState.ROLLED_BACK) { + unlockObjectRefs(); + this.state = TransactionState.ROLLED_BACK; + this.objectFilter.clearCache(); + + long end = System.nanoTime(); + long txDuration = end - this.startTime; + long closeDuration = end - start; + + if (this.txResult != null) { + this.txResult.clear(); + this.txResult.setState(this.state); + this.txResult.setStartTime(this.startTimeDate); + this.txResult.setTxDuration(txDuration); + this.txResult.setCloseDuration(closeDuration); + this.txResult.setRealm(this.realm.getRealmName()); + this.txResult.setModificationByKey(Collections. emptyMap()); + } + } + } + + @Override + public void autoCloseableCommit() throws XmlPersistenceException { + + long start = System.nanoTime(); + + try { + + if (this.verbose) { + String msg = "Committing {0} operations in TX...";//$NON-NLS-1$ + logger.info(MessageFormat.format(msg, this.objectFilter.sizeCache())); + } + + Set keySet = this.objectFilter.keySet(); + Map modifications; + if (this.txResult == null) + modifications = null; + else + modifications = new HashMap<>(keySet.size()); + + for (String key : keySet) { + + List removed = this.objectFilter.getRemoved(key); + if (removed.isEmpty()) { + if (this.verbose) + logger.info("No objects removed in this tx."); //$NON-NLS-1$ + } else { + if (this.verbose) + logger.info(removed.size() + " objects removed in this tx."); //$NON-NLS-1$ + + for (Object object : removed) { + @SuppressWarnings("unchecked") + PersistenceContext ctx = (PersistenceContext) object; + this.fileDao.performDelete(ctx); + } + } + + List updated = this.objectFilter.getUpdated(key); + if (updated.isEmpty()) { + if (this.verbose) + logger.info("No objects updated in this tx."); //$NON-NLS-1$ + } else { + if (this.verbose) + logger.info(updated.size() + " objects updated in this tx."); //$NON-NLS-1$ + + for (Object object : updated) { + @SuppressWarnings("unchecked") + PersistenceContext ctx = (PersistenceContext) object; + this.fileDao.performUpdate(ctx); + } + } + + List added = this.objectFilter.getAdded(key); + if (added.isEmpty()) { + if (this.verbose) + logger.info("No objects added in this tx."); //$NON-NLS-1$ + } else { + if (this.verbose) + logger.info(added.size() + " objects added in this tx."); //$NON-NLS-1$ + + for (Object object : added) { + @SuppressWarnings("unchecked") + PersistenceContext ctx = (PersistenceContext) object; + this.fileDao.performCreate(ctx); + } + } + + if (modifications != null) { + ModificationResult result = new ModificationResult(key, added, updated, removed); + modifications.put(key, result); + } + } + + if (this.txResult != null) { + this.txResult.clear(); + this.txResult.setState(TransactionState.COMMITTED); + this.txResult.setModificationByKey(modifications); + } + + } catch (Exception e) { + + if (this.txResult == null) { + + long end = System.nanoTime(); + long txDuration = end - this.startTime; + long closeDuration = end - start; + + StringBuilder sb = new StringBuilder(); + sb.append("TX has failed after "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(txDuration)); + sb.append(" with close operation taking "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(closeDuration)); + logger.info(sb.toString()); + + throw e; + } + + this.txResult.clear(); + this.txResult.setState(TransactionState.FAILED); + this.txResult.setModificationByKey(Collections. emptyMap()); + this.txResult.setFailCause(e); + + } finally { + + // clean up + unlockObjectRefs(); + this.objectFilter.clearCache(); + } + + long end = System.nanoTime(); + long txDuration = end - this.startTime; + long closeDuration = end - start; + + if (this.txResult == null) { + + StringBuilder sb = new StringBuilder(); + sb.append("TX was completed after "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(txDuration)); + sb.append(" with close operation taking "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(closeDuration)); + logger.info(sb.toString()); + + } else { + + this.txResult.setStartTime(this.startTimeDate); + this.txResult.setTxDuration(txDuration); + this.txResult.setCloseDuration(closeDuration); + this.txResult.setRealm(this.realm.getRealmName()); + + if (this.txResult.getState() == TransactionState.FAILED) { + String msg = "Failed to commit TX due to underlying exception: {0}"; //$NON-NLS-1$ + String causeMsg = this.txResult.getFailCause() == null ? null : this.txResult.getFailCause() + .getMessage(); + msg = MessageFormat.format(msg, causeMsg); + throw new XmlPersistenceException(msg, this.txResult.getFailCause()); + } + } + } + + @SuppressWarnings("rawtypes") + private void unlockObjectRefs() { + List lockedObjects = this.objectFilter.getAll(PersistenceContext.class); + for (PersistenceContext lockedObject : lockedObjects) { + lockedObject.getObjectRef().unlock(); + } + } + + @Override + public boolean isOpen() { + return this.state == TransactionState.OPEN; + } + + @Override + public void setIoMode(IoMode ioMode) { + this.ioMode = ioMode; + } + + @Override + public IoMode getIoMode() { + return this.ioMode; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/PathBuilder.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/PathBuilder.java new file mode 100644 index 000000000..1fb7ed25d --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/impl/PathBuilder.java @@ -0,0 +1,123 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.impl; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.PropertiesHelper; +import li.strolch.utils.helper.StringHelper; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.XmlPersistenceException; + +/** + * @author Robert von Burg + */ +public class PathBuilder { + + private static final Logger logger = LoggerFactory.getLogger(PathBuilder.class); + + public static final String FILE_EXT = ".xml"; //$NON-NLS-1$ + public static final int EXT_LENGTH = PathBuilder.FILE_EXT.length(); + + private final String basePath; + + public PathBuilder(String realm, Properties properties) { + + // get properties + String context = PathBuilder.class.getSimpleName(); + String basePath = PropertiesHelper.getProperty(properties, context, PersistenceConstants.PROP_BASEPATH, null); + + // validate base path exists and is writable + File basePathF = new File(basePath); + if (!basePathF.exists()) + throw new XmlPersistenceException(MessageFormat.format("The database store path does not exist at {0}", //$NON-NLS-1$ + basePathF.getAbsolutePath())); + if (!basePathF.canWrite()) + throw new XmlPersistenceException(MessageFormat.format("The database store path is not writeable at {0}", //$NON-NLS-1$ + basePathF.getAbsolutePath())); + + File realmPathF = new File(basePathF, realm); + if (!realmPathF.exists() && !realmPathF.mkdir()) + throw new XmlPersistenceException(MessageFormat.format("Could not create path for realm {0} at {1}", //$NON-NLS-1$ + realm, basePathF.getAbsolutePath())); + + // we want a clean base path + String canonicalBasePath; + try { + canonicalBasePath = realmPathF.getCanonicalPath(); + } catch (IOException e) { + throw new XmlPersistenceException(MessageFormat.format( + "Failed to build canonical path from {0}", realmPathF.getAbsolutePath()), e); //$NON-NLS-1$ + } + + // this.basePathF = basePathF; + this.basePath = canonicalBasePath; + logger.info(MessageFormat.format("Using base path {0}", this.basePath)); //$NON-NLS-1$ + } + + String getFilename(String id) { + return id.concat(PathBuilder.FILE_EXT); + } + + String getPathAsString(String type, String subType, String id) { + StringBuilder sb = new StringBuilder(this.basePath); + if (StringHelper.isNotEmpty(type)) { + sb.append(File.separatorChar); + sb.append(type); + } + if (StringHelper.isNotEmpty(subType)) { + sb.append(File.separatorChar); + sb.append(subType); + } + if (StringHelper.isNotEmpty(id)) { + sb.append(File.separatorChar); + sb.append(getFilename(id)); + } + + return sb.toString(); + } + + public File getRootPath() { + File path = new File(getPathAsString(null, null, null)); + return path; + } + + public File getTypePath(String type) { + File path = new File(getPathAsString(type, null, null)); + return path; + } + + public File getSubTypePath(String type, String subType) { + File path = new File(getPathAsString(type, subType, null)); + return path; + } + + public File getIdOfTypePath(String type, String id) { + File path = new File(getPathAsString(type, null, id)); + return path; + } + + public File getIdOfSubTypePath(String type, String subType, String id) { + File path = new File(getPathAsString(type, subType, id)); + return path; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/IdOfSubTypeRef.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/IdOfSubTypeRef.java new file mode 100644 index 000000000..c4a3c1031 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/IdOfSubTypeRef.java @@ -0,0 +1,137 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.io.File; +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.api.PersistenceContextFactoryDelegator; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; + +public class IdOfSubTypeRef extends ObjectRef { + + private final String type; + private final String subType; + private final String id; + + public IdOfSubTypeRef(String realmName, String type, String subType, String id) { + super(realmName, RefNameCreator.createIdOfSubTypeName(realmName, type, subType, id)); + this.type = type; + this.subType = subType; + this.id = id; + } + + @Override + public String getType() { + return this.type; + } + + public String getSubType() { + return this.subType; + } + + /** + * @return the id + */ + public String getId() { + return this.id; + } + + @Override + public boolean isRoot() { + return false; + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public ObjectRef getParent(PersistenceTransaction tx) { + return tx.getRealm().getObjectRefCache().getSubTypeRef(this.type, this.subType); + } + + @Override + public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) { + String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) { + String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public File getPath(PathBuilder pathBuilder) { + return pathBuilder.getIdOfSubTypePath(this.type, this.subType, this.id); + } + + @Override + public PersistenceContext createPersistenceContext(PersistenceTransaction tx) { + PersistenceContextFactoryDelegator ctxFactoryDelegator = tx.getRealm().getCtxFactoryDelegator(); + PersistenceContextFactory persistenceContextFactory = ctxFactoryDelegator. getCtxFactory(this.type); + return persistenceContextFactory.createCtx(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.id == null) ? 0 : this.id.hashCode()); + result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode()); + result = prime * result + ((this.subType == null) ? 0 : this.subType.hashCode()); + result = prime * result + ((this.type == null) ? 0 : this.type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + IdOfSubTypeRef other = (IdOfSubTypeRef) obj; + if (this.realmName == null) { + if (other.realmName != null) + return false; + } else if (!this.realmName.equals(other.realmName)) + return false; + if (this.id == null) { + if (other.id != null) + return false; + } else if (!this.id.equals(other.id)) + return false; + if (this.subType == null) { + if (other.subType != null) + return false; + } else if (!this.subType.equals(other.subType)) + return false; + if (this.type == null) { + if (other.type != null) + return false; + } else if (!this.type.equals(other.type)) + return false; + return true; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/IdOfTypeRef.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/IdOfTypeRef.java new file mode 100644 index 000000000..906a29118 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/IdOfTypeRef.java @@ -0,0 +1,125 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.io.File; +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.api.PersistenceContextFactoryDelegator; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; + +public class IdOfTypeRef extends ObjectRef { + + private final String type; + private final String id; + + public IdOfTypeRef(String realmName, String type, String id) { + super(realmName, RefNameCreator.createIdOfTypeName(realmName, type, id)); + this.type = type; + this.id = id; + } + + @Override + public String getType() { + return this.type; + } + + /** + * @return the id + */ + public String getId() { + return this.id; + } + + @Override + public boolean isRoot() { + return false; + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public ObjectRef getParent(PersistenceTransaction tx) { + return tx.getRealm().getObjectRefCache().getTypeRef(this.type); + } + + @Override + public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) { + String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) { + String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public File getPath(PathBuilder pathBuilder) { + return pathBuilder.getIdOfTypePath(this.type, this.id); + } + + @Override + public PersistenceContext createPersistenceContext(PersistenceTransaction tx) { + PersistenceContextFactoryDelegator ctxFactoryDelegator = tx.getRealm().getCtxFactoryDelegator(); + PersistenceContextFactory persistenceContextFactory = ctxFactoryDelegator. getCtxFactory(this.type); + return persistenceContextFactory.createCtx(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.id == null) ? 0 : this.id.hashCode()); + result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode()); + result = prime * result + ((this.type == null) ? 0 : this.type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + IdOfTypeRef other = (IdOfTypeRef) obj; + if (this.realmName == null) { + if (other.realmName != null) + return false; + } else if (!this.realmName.equals(other.realmName)) + return false; + if (this.id == null) { + if (other.id != null) + return false; + } else if (!this.id.equals(other.id)) + return false; + if (this.type == null) { + if (other.type != null) + return false; + } else if (!this.type.equals(other.type)) + return false; + return true; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java new file mode 100644 index 000000000..7734a0049 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java @@ -0,0 +1,69 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.text.MessageFormat; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.StringHelper; +import li.strolch.xmlpers.api.XmlPersistenceException; + +public class LockableObject { + + private static final Logger logger = LoggerFactory.getLogger(LockableObject.class); + private static long tryLockTime = 10000L; + + private final ReentrantLock lock; + + public LockableObject() { + this.lock = new ReentrantLock(true); + } + + public static long getLockTime() { + return tryLockTime; + } + + /** + * @see java.util.concurrent.locks.ReentrantLock#tryLock(long, TimeUnit) + */ + public void lock() { + try { + + if (!this.lock.tryLock(tryLockTime, TimeUnit.MILLISECONDS)) { + String msg = "Failed to acquire lock after {0} for {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, StringHelper.formatMillisecondsDuration(tryLockTime), toString()); + throw new XmlPersistenceException(msg); + } + if (logger.isDebugEnabled()) + logger.debug("locked " + toString()); //$NON-NLS-1$ + } catch (InterruptedException e) { + throw new XmlPersistenceException("Thread interrupted: " + e.getMessage(), e); //$NON-NLS-1$ + } + } + + /** + * @see java.util.concurrent.locks.ReentrantLock#unlock() + */ + public void unlock() { + this.lock.unlock(); + if (logger.isDebugEnabled()) + logger.debug("unlocking " + toString()); //$NON-NLS-1$ + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/ObjectRef.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/ObjectRef.java new file mode 100644 index 000000000..c03d5dbb3 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/ObjectRef.java @@ -0,0 +1,68 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.io.File; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; + +public abstract class ObjectRef extends LockableObject { + + protected final String realmName; + protected final String name; + + protected ObjectRef(String realmName, String name) { + this.realmName = realmName; + this.name = name; + } + + public String getRealmName() { + return this.realmName; + } + + public String getName() { + return this.name; + } + + public abstract boolean isRoot(); + + public abstract boolean isLeaf(); + + public abstract String getType(); + + public abstract ObjectRef getParent(PersistenceTransaction tx); + + public abstract ObjectRef getChildIdRef(PersistenceTransaction tx, String id); + + public abstract ObjectRef getChildTypeRef(PersistenceTransaction tx, String type); + + public abstract File getPath(PathBuilder pathBuilder); + + public abstract PersistenceContext createPersistenceContext(PersistenceTransaction tx); + + @Override + public String toString() { + return getName(); + } + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/ObjectReferenceCache.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/ObjectReferenceCache.java new file mode 100644 index 000000000..a2156141d --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/ObjectReferenceCache.java @@ -0,0 +1,95 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.util.HashMap; +import java.util.Map; + +import li.strolch.utils.helper.StringHelper; + +public class ObjectReferenceCache { + + private final String realmName; + private final RootRef rootRef; + private final Map typeRefMap; + private final Map subTypeRefMap; + private final Map idOfTypeRefMap; + private final Map idOfSubTypeRefMap; + + public ObjectReferenceCache(String realmName) { + if (StringHelper.isEmpty(realmName)) + throw new IllegalArgumentException("Realm name may not be empty!"); //$NON-NLS-1$ + + this.realmName = realmName; + this.rootRef = new RootRef(this.realmName); + this.typeRefMap = new HashMap<>(); + this.subTypeRefMap = new HashMap<>(); + this.idOfTypeRefMap = new HashMap<>(); + this.idOfSubTypeRefMap = new HashMap<>(); + } + + public String getRealmName() { + return this.realmName; + } + + public synchronized RootRef getRootRef() { + return this.rootRef; + } + + public synchronized TypeRef getTypeRef(String type) { + String key = RefNameCreator.createTypeName(this.realmName, type); + TypeRef ref = this.typeRefMap.get(key); + if (ref == null) { + ref = new TypeRef(this.realmName, type); + this.typeRefMap.put(key, ref); + } + + return ref; + } + + public synchronized SubTypeRef getSubTypeRef(String type, String subType) { + String key = RefNameCreator.createSubTypeName(this.realmName, type, subType); + SubTypeRef ref = this.subTypeRefMap.get(key); + if (ref == null) { + ref = new SubTypeRef(this.realmName, type, subType); + this.subTypeRefMap.put(key, ref); + } + + return ref; + } + + public synchronized IdOfTypeRef getIdOfTypeRef(String type, String id) { + String key = RefNameCreator.createIdOfTypeName(this.realmName, type, id); + IdOfTypeRef idRef = this.idOfTypeRefMap.get(key); + if (idRef == null) { + idRef = new IdOfTypeRef(this.realmName, type, id); + this.idOfTypeRefMap.put(key, idRef); + } + + return idRef; + } + + public synchronized IdOfSubTypeRef getIdOfSubTypeRef(String type, String subType, String id) { + String key = RefNameCreator.createIdOfSubTypeName(this.realmName, type, subType, id); + IdOfSubTypeRef idRef = this.idOfSubTypeRefMap.get(key); + if (idRef == null) { + idRef = new IdOfSubTypeRef(this.realmName, type, subType, id); + this.idOfSubTypeRefMap.put(key, idRef); + } + + return idRef; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/RefNameCreator.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/RefNameCreator.java new file mode 100644 index 000000000..5c1c87576 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/RefNameCreator.java @@ -0,0 +1,82 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import li.strolch.utils.helper.StringHelper; + +public class RefNameCreator { + + protected static final String SLASH = "/"; //$NON-NLS-1$ + + // FIXME validate each name part that it is a valid literal for file names... + + public static String createRootName(String realmName) { + assertRealmName(realmName); + return SLASH + realmName + SLASH; + } + + public static String createTypeName(String realmName, String type) { + assertRealmName(realmName); + assertType(type); + return SLASH + realmName + SLASH + type + SLASH; + } + + public static String createIdOfTypeName(String realmName, String type, String id) { + assertRealmName(realmName); + assertType(type); + assertId(id); + return SLASH + realmName + SLASH + type + SLASH + id; + } + + public static String createSubTypeName(String realmName, String type, String subType) { + assertRealmName(realmName); + assertType(type); + assertSubType(subType); + return SLASH + realmName + SLASH + type + SLASH + subType + SLASH; + } + + public static String createIdOfSubTypeName(String realmName, String type, String subType, String id) { + assertRealmName(realmName); + assertType(type); + assertSubType(subType); + assertId(id); + return SLASH + realmName + SLASH + type + SLASH + subType + SLASH + id; + } + + private static void assertRealmName(String realmName) { + if (StringHelper.isEmpty(realmName)) { + throw new IllegalArgumentException("Realm name may not be empty!"); //$NON-NLS-1$ + } + } + + private static void assertType(String type) { + if (StringHelper.isEmpty(type)) { + throw new IllegalArgumentException("type may not be empty!"); //$NON-NLS-1$ + } + } + + private static void assertSubType(String subType) { + if (StringHelper.isEmpty(subType)) { + throw new IllegalArgumentException("subType may not be empty!"); //$NON-NLS-1$ + } + } + + private static void assertId(String id) { + if (StringHelper.isEmpty(id)) { + throw new IllegalArgumentException("id may not be empty!"); //$NON-NLS-1$ + } + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/RootRef.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/RootRef.java new file mode 100644 index 000000000..03677a366 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/RootRef.java @@ -0,0 +1,99 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.io.File; +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; + +public class RootRef extends ObjectRef { + + public RootRef(String realmName) { + super(realmName, RefNameCreator.createRootName(realmName)); + } + + @Override + public boolean isRoot() { + return true; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public String getType() { + String msg = MessageFormat.format("RootRef has no type: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public ObjectRef getParent(PersistenceTransaction tx) { + String msg = MessageFormat.format("RootRef has no parent: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) { + String msg = MessageFormat.format("RootRef has no child id: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) { + return tx.getRealm().getObjectRefCache().getTypeRef(type); + } + + @Override + public File getPath(PathBuilder pathBuilder) { + return pathBuilder.getRootPath(); + } + + @Override + public PersistenceContext createPersistenceContext(PersistenceTransaction tx) { + String msg = MessageFormat.format("{0} is not a leaf and can thus not have a Persistence Context", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RootRef other = (RootRef) obj; + if (this.realmName == null) { + if (other.realmName != null) + return false; + } else if (!this.realmName.equals(other.realmName)) + return false; + return true; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/SubTypeRef.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/SubTypeRef.java new file mode 100644 index 000000000..a94c5a46d --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/SubTypeRef.java @@ -0,0 +1,118 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.io.File; +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; + +public class SubTypeRef extends ObjectRef { + + private final String type; + private final String subType; + + public SubTypeRef(String realmName, String type, String subType) { + super(realmName, RefNameCreator.createSubTypeName(realmName, type, subType)); + this.type = type; + this.subType = subType; + } + + @Override + public String getType() { + return this.type; + } + + public String getSubType() { + return this.subType; + } + + @Override + public boolean isRoot() { + return false; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public ObjectRef getParent(PersistenceTransaction tx) { + return tx.getRealm().getObjectRefCache().getTypeRef(this.type); + } + + @Override + public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) { + return tx.getRealm().getObjectRefCache().getIdOfSubTypeRef(this.type, this.subType, id); + } + + @Override + public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) { + String msg = MessageFormat.format("A SubType has no child type: {0}", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public File getPath(PathBuilder pathBuilder) { + return pathBuilder.getSubTypePath(this.type, this.subType); + } + + @Override + public PersistenceContext createPersistenceContext(PersistenceTransaction tx) { + String msg = MessageFormat.format("{0} is not a leaf and can thus not have a Persistence Context", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode()); + result = prime * result + ((this.subType == null) ? 0 : this.subType.hashCode()); + result = prime * result + ((this.type == null) ? 0 : this.type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SubTypeRef other = (SubTypeRef) obj; + if (this.realmName == null) { + if (other.realmName != null) + return false; + } else if (!this.realmName.equals(other.realmName)) + return false; + if (this.subType == null) { + if (other.subType != null) + return false; + } else if (!this.subType.equals(other.subType)) + return false; + if (this.type == null) { + if (other.type != null) + return false; + } else if (!this.type.equals(other.type)) + return false; + return true; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/TypeRef.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/TypeRef.java new file mode 100644 index 000000000..90e8f50e1 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/objref/TypeRef.java @@ -0,0 +1,105 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.objref; + +import java.io.File; +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; + +public class TypeRef extends ObjectRef { + + private final String type; + + public TypeRef(String realmName, String type) { + super(realmName, RefNameCreator.createTypeName(realmName, type)); + this.type = type; + } + + @Override + public String getType() { + return this.type; + } + + @Override + public boolean isRoot() { + return false; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public ObjectRef getParent(PersistenceTransaction tx) { + return tx.getRealm().getObjectRefCache().getRootRef(); + } + + @Override + public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) { + return tx.getRealm().getObjectRefCache().getIdOfTypeRef(this.type, id); + } + + @Override + public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) { + return tx.getRealm().getObjectRefCache().getSubTypeRef(this.type, type); + } + + @Override + public File getPath(PathBuilder pathBuilder) { + return pathBuilder.getTypePath(this.type); + } + + @Override + public PersistenceContext createPersistenceContext(PersistenceTransaction tx) { + String msg = MessageFormat.format("{0} is not a leaf and can thus not have a Persistence Context", getName()); //$NON-NLS-1$ + throw new UnsupportedOperationException(msg); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode()); + result = prime * result + ((this.type == null) ? 0 : this.type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TypeRef other = (TypeRef) obj; + if (this.realmName == null) { + if (other.realmName != null) + return false; + } else if (!this.realmName.equals(other.realmName)) + return false; + if (this.type == null) { + if (other.type != null) + return false; + } else if (!this.type.equals(other.type)) + return false; + return true; + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/AssertionUtil.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/AssertionUtil.java new file mode 100644 index 000000000..5419da935 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/AssertionUtil.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.util; + +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.objref.ObjectRef; + +public class AssertionUtil { + + public static void assertNotNull(Object object) { + if (object == null) + throw new RuntimeException("Object may not be null!"); //$NON-NLS-1$ + } + + public static void assertObjectRead(PersistenceContext context) { + if (context.getObject() == null) { + String msg = "Failed to read object with for {0}"; //$NON-NLS-1$ + ObjectRef objectRef = context.getObjectRef(); + msg = MessageFormat.format(msg, objectRef.getName()); + throw new RuntimeException(msg); + } + } + + public static void assertIsIdRef(ObjectRef objectRef) { + if (!objectRef.isLeaf()) { + String msg = "Expected IdRef not {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName()); + throw new IllegalArgumentException(msg); + } + } + + public static void assertIsNotIdRef(ObjectRef objectRef) { + if (objectRef.isLeaf()) { + String msg = "IdRef not expected {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName()); + throw new IllegalArgumentException(msg); + } + } + + public static void assertIsNotRootRef(ObjectRef objectRef) { + if (objectRef.isRoot()) { + String msg = "RootRef not expected {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, objectRef.getName()); + throw new IllegalArgumentException(msg); + } + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/DomUtil.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/DomUtil.java new file mode 100644 index 000000000..fa74f83c1 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/DomUtil.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.util; + +import java.text.MessageFormat; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import li.strolch.xmlpers.api.XmlPersistenceException; + +/** + * @author Robert von Burg + * + */ +public class DomUtil { + + public static DocumentBuilder createDocumentBuilder() { + try { + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + return docBuilder; + } catch (ParserConfigurationException e) { + String msg = "No Xml Parser could be loaded: {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, e.getMessage()); + throw new XmlPersistenceException(msg, e); + } + } +} diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/FilenameUtility.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/FilenameUtility.java new file mode 100644 index 000000000..33cb41f44 --- /dev/null +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/util/FilenameUtility.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.util; + +import java.text.MessageFormat; + +import li.strolch.xmlpers.api.XmlPersistenceException; +import li.strolch.xmlpers.impl.PathBuilder; + +public class FilenameUtility { + + public static String getId(String filename) { + assertFilename(filename); + return filename.substring(0, filename.length() - PathBuilder.EXT_LENGTH); + } + + public static void assertFilename(String filename) { + if (filename.charAt(filename.length() - PathBuilder.EXT_LENGTH) != '.') { + String msg = "The filename does not have a . (dot) at index {0}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, (filename.length() - PathBuilder.EXT_LENGTH)); + throw new XmlPersistenceException(msg); + } + } + +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/AbstractPersistenceTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/AbstractPersistenceTest.java new file mode 100644 index 000000000..dcdaa4d90 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/AbstractPersistenceTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import java.io.File; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.utils.helper.FileHelper; +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceManager; +import li.strolch.xmlpers.api.PersistenceManagerLoader; +import li.strolch.xmlpers.test.impl.BookContextFactory; +import li.strolch.xmlpers.test.impl.MyModelContextFactory; +import li.strolch.xmlpers.test.impl.TestConstants; +import li.strolch.xmlpers.test.model.Book; +import li.strolch.xmlpers.test.model.MyModel; + +public abstract class AbstractPersistenceTest { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractPersistenceTest.class); + + protected PersistenceManager persistenceManager; + + @SuppressWarnings("nls") + protected static void cleanPath(String path) { + + File file = new File(path).getAbsoluteFile(); + File parent = file.getParentFile(); + if (!parent.getAbsolutePath().endsWith("/target/db")) + throw new RuntimeException("Bad parent! Must be /target/db/: " + parent); + if (!parent.exists() && !parent.mkdirs()) + throw new RuntimeException("Failed to create path " + parent); + + if (file.exists() && file.isDirectory()) + if (!FileHelper.deleteFiles(file.listFiles(), true)) + throw new RuntimeException("Could not clean up path " + file.getAbsolutePath()); + + if (!file.exists() && !file.mkdir()) + throw new RuntimeException("Failed to create path " + file); + + File domFile = new File(file, IoMode.DOM.name()); + if (!domFile.mkdir()) + throw new RuntimeException("Failed to create path " + domFile); + + File saxFile = new File(file, IoMode.SAX.name()); + if (!saxFile.mkdir()) + throw new RuntimeException("Failed to create path " + saxFile); + } + + protected void setup(Properties properties) { + properties.setProperty(PersistenceConstants.PROP_VERBOSE, "true"); //$NON-NLS-1$ + this.persistenceManager = PersistenceManagerLoader.load(properties); + this.persistenceManager.getCtxFactory().registerPersistenceContextFactory(MyModel.class, + TestConstants.TYPE_RES, new MyModelContextFactory()); + this.persistenceManager.getCtxFactory().registerPersistenceContextFactory(Book.class, TestConstants.TYPE_BOOK, + new BookContextFactory()); + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/FileDaoTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/FileDaoTest.java new file mode 100644 index 000000000..c80114a63 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/FileDaoTest.java @@ -0,0 +1,122 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import static li.strolch.xmlpers.test.model.ModelBuilder.assertResource; +import static li.strolch.xmlpers.test.model.ModelBuilder.assertResourceUpdated; +import static li.strolch.xmlpers.test.model.ModelBuilder.createResource; +import static li.strolch.xmlpers.test.model.ModelBuilder.updateResource; +import static org.junit.Assert.assertNull; + +import java.util.Properties; + +import org.junit.BeforeClass; +import org.junit.Test; + +import li.strolch.xmlpers.api.FileDao; +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.api.PersistenceContextFactoryDelegator; +import li.strolch.xmlpers.api.PersistenceManager; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.impl.DefaultPersistenceRealm; +import li.strolch.xmlpers.impl.DefaultPersistenceTransaction; +import li.strolch.xmlpers.impl.PathBuilder; +import li.strolch.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.test.model.MyModel; + +/** + * @author Robert von Burg + * + */ +@SuppressWarnings("nls") +public class FileDaoTest extends AbstractPersistenceTest { + + private static final String TEST_PATH = "target/db/FileDaoTest/"; + private static final boolean VERBOSE = true; + private DefaultPersistenceRealm realm; + private PathBuilder pathBuilder; + + @BeforeClass + public static void beforeClass() { + cleanPath(TEST_PATH); + } + + private void setup(IoMode ioMode) { + Properties properties = new Properties(); + properties.setProperty(PersistenceConstants.PROP_BASEPATH, TEST_PATH + ioMode.name()); + setup(properties); + + ObjectReferenceCache objectRefCache = new ObjectReferenceCache(PersistenceManager.DEFAULT_REALM); + this.pathBuilder = new PathBuilder(PersistenceManager.DEFAULT_REALM, properties); + this.realm = new DefaultPersistenceRealm(PersistenceManager.DEFAULT_REALM, this.persistenceManager, + this.persistenceManager.getCtxFactory(), this.pathBuilder, objectRefCache); + } + + @Test + public void testCrudSax() { + setup(IoMode.SAX); + try (PersistenceTransaction tx = new DefaultPersistenceTransaction(this.realm, VERBOSE)) { + FileDao fileDao = new FileDao(tx, this.pathBuilder, VERBOSE); + tx.setIoMode(IoMode.SAX); + testCrud(this.realm.getCtxFactoryDelegator(), fileDao); + } + } + + @Test + public void testCrudDom() { + setup(IoMode.DOM); + try (PersistenceTransaction tx = new DefaultPersistenceTransaction(this.realm, VERBOSE)) { + FileDao fileDao = new FileDao(tx, this.pathBuilder, VERBOSE); + tx.setIoMode(IoMode.DOM); + testCrud(this.realm.getCtxFactoryDelegator(), fileDao); + } + } + + private void testCrud(PersistenceContextFactoryDelegator ctxFactoryDelegator, FileDao fileDao) { + + MyModel resource = createResource(); + assertResource(resource); + Class classType = resource.getClass(); + PersistenceContextFactory ctxFactory = ctxFactoryDelegator.getCtxFactory(classType); + ObjectReferenceCache objectRefCache = this.realm.getObjectRefCache(); + PersistenceContext context = ctxFactory.createCtx(objectRefCache, resource); + context.setObject(resource); + fileDao.performCreate(context); + + context.setObject(null); + fileDao.performRead(context); + assertResource(context.getObject()); + + updateResource(context.getObject()); + fileDao.performUpdate(context); + + context.setObject(null); + fileDao.performRead(context); + assertResourceUpdated(context.getObject()); + + fileDao.performDelete(context); + + context.setObject(null); + fileDao.performRead(context); + assertNull(context.getObject()); + + context.setObject(createResource()); + fileDao.performCreate(context); + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/LockingTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/LockingTest.java new file mode 100644 index 000000000..2b1e0cb1a --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/LockingTest.java @@ -0,0 +1,233 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import static li.strolch.xmlpers.test.impl.TestConstants.TYPE_RES; +import static li.strolch.xmlpers.test.model.ModelBuilder.RES_TYPE; +import static li.strolch.xmlpers.test.model.ModelBuilder.createResource; +import static li.strolch.xmlpers.test.model.ModelBuilder.updateResource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.LockableObject; +import li.strolch.xmlpers.test.model.MyModel; + +/** + * @author Robert von Burg + * + */ +public class LockingTest extends AbstractPersistenceTest { + + private static final String BASE_PATH = "target/db/LockingTest/"; //$NON-NLS-1$ + + private long waitForWorkersTime; + private boolean run; + + @BeforeClass + public static void beforeClass() { + cleanPath(BASE_PATH); + } + + @Before + public void before() { + Properties properties = new Properties(); + properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASE_PATH + IoMode.DOM.name()); + properties.setProperty(PersistenceConstants.PROP_LOCK_TIME_MILLIS, Long.toString(500L)); + setup(properties); + + this.waitForWorkersTime = LockableObject.getLockTime() + getWaitForWorkersTime() + 300L; + } + + @Test + public void shouldLockObjects() throws InterruptedException { + + List workers = new ArrayList<>(5); + + String resoureId = "worker"; //$NON-NLS-1$ + for (int i = 0; i < 5; i++) { + String workerName = resoureId + "_" + i; //$NON-NLS-1$ + CreateResourceWorker worker = new CreateResourceWorker(workerName, workerName); + worker.start(); + workers.add(worker); + logger.info("Setup thread " + worker.getName()); //$NON-NLS-1$ + } + + int nrOfSuccess = runWorkers(workers); + + assertEquals("Only one thread should be able to perform the TX!", 5, nrOfSuccess); //$NON-NLS-1$ + } + + @Test + public void shouldFailIfResourceAlreadyExists() throws InterruptedException { + + List workers = new ArrayList<>(5); + + String resourceId = "createWorkerRes"; //$NON-NLS-1$ + for (int i = 0; i < 5; i++) { + String workerName = resourceId + "_" + i; //$NON-NLS-1$ + CreateResourceWorker worker = new CreateResourceWorker(workerName, resourceId); + worker.start(); + workers.add(worker); + logger.info("Setup thread " + worker.getName()); //$NON-NLS-1$ + } + + int nrOfSuccess = runWorkers(workers); + + assertEquals("Only one thread should be able to perform the TX!", 1, nrOfSuccess); //$NON-NLS-1$ + } + + @Test + public void shouldFailUpdateIfLockNotAcquirable() throws InterruptedException { + + // prepare workers + List workers = new ArrayList<>(5); + String resourceId = "updatWorkerRes"; //$NON-NLS-1$ + for (int i = 0; i < 5; i++) { + String workerName = resourceId + "_" + i; //$NON-NLS-1$ + UpdateResourceWorker worker = new UpdateResourceWorker(workerName, resourceId); + worker.start(); + workers.add(worker); + logger.info("Setup thread " + worker.getName()); //$NON-NLS-1$ + } + + // create resource which is to be updated + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + MyModel resource = createResource(resourceId); + tx.getObjectDao().add(resource); + } + + int nrOfSuccess = runWorkers(workers); + + assertEquals("Only one thread should be able to perform the TX!", 1, nrOfSuccess); //$NON-NLS-1$ + } + + private int runWorkers(List workers) throws InterruptedException { + + setRun(true); + + for (AbstractWorker worker : workers) { + worker.join(getWaitForWorkersTime() + 2000L); + } + + int nrOfSuccess = 0; + for (AbstractWorker worker : workers) { + if (worker.isSuccess()) + nrOfSuccess++; + } + + return nrOfSuccess; + } + + public long getWaitForWorkersTime() { + return this.waitForWorkersTime; + } + + public boolean isRun() { + return this.run; + } + + public void setRun(boolean run) { + this.run = run; + } + + public abstract class AbstractWorker extends Thread { + + protected boolean success; + protected String resourceId; + + public AbstractWorker(String name, String resourceId) { + super(name); + this.resourceId = resourceId; + } + + @Override + public void run() { + + logger.info("Waiting for ok to work..."); //$NON-NLS-1$ + while (!isRun()) { + try { + Thread.sleep(10L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + logger.info("Starting work..."); //$NON-NLS-1$ + try (PersistenceTransaction tx = LockingTest.this.persistenceManager.openTx()) { + doWork(tx); + + try { + Thread.sleep(getWaitForWorkersTime()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + this.success = true; + } + + logger.info("Work completed."); //$NON-NLS-1$ + } + + protected abstract void doWork(PersistenceTransaction tx); + + public boolean isSuccess() { + return this.success; + } + } + + public class CreateResourceWorker extends AbstractWorker { + + public CreateResourceWorker(String name, String resourceId) { + super(name, resourceId); + } + + @Override + protected void doWork(PersistenceTransaction tx) { + MyModel resource = createResource(this.resourceId); + tx.getObjectDao().add(resource); + } + } + + public class UpdateResourceWorker extends AbstractWorker { + + public UpdateResourceWorker(String name, String resourceId) { + super(name, resourceId); + } + + @Override + protected void doWork(PersistenceTransaction tx) { + + IdOfSubTypeRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, RES_TYPE, this.resourceId); + MyModel resource = tx.getObjectDao().queryById(objectRef); + assertNotNull(resource); + updateResource(resource); + + tx.getObjectDao().update(resource); + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/ObjectDaoBookTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/ObjectDaoBookTest.java new file mode 100644 index 000000000..c457d769c --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/ObjectDaoBookTest.java @@ -0,0 +1,226 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import static li.strolch.xmlpers.test.model.ModelBuilder.BOOK_ID; +import static li.strolch.xmlpers.test.model.ModelBuilder.assertBook; +import static li.strolch.xmlpers.test.model.ModelBuilder.assertBookUpdated; +import static li.strolch.xmlpers.test.model.ModelBuilder.createBook; +import static li.strolch.xmlpers.test.model.ModelBuilder.updateBook; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; + +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.ObjectDao; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.objref.IdOfTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.TypeRef; +import li.strolch.xmlpers.test.impl.TestConstants; +import li.strolch.xmlpers.test.model.Book; + +/** + * @author Robert von Burg + * + */ +public class ObjectDaoBookTest extends AbstractPersistenceTest { + + private static final String BASEPATH = "target/db/ObjectDaoTest/"; //$NON-NLS-1$ + + @Before + public void before() { + cleanPath(BASEPATH); + } + + private void setup(IoMode ioMode) { + Properties properties = new Properties(); + properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASEPATH + ioMode.name()); + setup(properties); + } + + @Test + public void testCrudSax() { + setup(IoMode.SAX); + testCrud(IoMode.SAX); + } + + @Test + public void testCrudDom() { + setup(IoMode.DOM); + testCrud(IoMode.DOM); + } + + private PersistenceTransaction freshTx(IoMode ioMode) { + PersistenceTransaction tx = this.persistenceManager.openTx(); + tx.setIoMode(ioMode); + return tx; + } + + private void testCrud(IoMode ioMode) { + + ObjectDao objectDao; + + // create new book + Book book = createBook(); + try (PersistenceTransaction tx = freshTx(ioMode);) { + objectDao = tx.getObjectDao(); + objectDao.add(book); + } + + // read book + try (PersistenceTransaction tx = freshTx(ioMode);) { + IdOfTypeRef bookRef = tx.getObjectRefCache() + .getIdOfTypeRef(TestConstants.TYPE_BOOK, Long.toString(BOOK_ID)); + objectDao = tx.getObjectDao(); + book = objectDao.queryById(bookRef); + assertBook(book); + + // modify book + updateBook(book); + objectDao.update(book); + } + + // read modified book + try (PersistenceTransaction tx = freshTx(ioMode);) { + IdOfTypeRef bookRef = tx.getObjectRefCache() + .getIdOfTypeRef(TestConstants.TYPE_BOOK, Long.toString(BOOK_ID)); + objectDao = tx.getObjectDao(); + book = objectDao.queryById(bookRef); + assertBookUpdated(book); + } + + // delete book + try (PersistenceTransaction tx = freshTx(ioMode);) { + objectDao = tx.getObjectDao(); + objectDao.remove(book); + } + + // fail to read + try (PersistenceTransaction tx = freshTx(ioMode);) { + IdOfTypeRef bookRef = tx.getObjectRefCache() + .getIdOfTypeRef(TestConstants.TYPE_BOOK, Long.toString(BOOK_ID)); + objectDao = tx.getObjectDao(); + book = objectDao.queryById(bookRef); + assertNull(book); + + // and create again + book = createBook(); + assertBook(book); + objectDao.add(book); + } + } + + @Test + public void testBulkSax() { + setup(IoMode.SAX); + testBulk(IoMode.SAX); + } + + @Test + public void testBulkDom() { + setup(IoMode.DOM); + testBulk(IoMode.DOM); + } + + private void testBulk(IoMode ioMode) { + + // create a list of books + List books = new ArrayList<>(10); + for (int i = 0; i < 10; i++) { + long id = i; + String title = "Bulk Test Book. " + i; //$NON-NLS-1$ + String author = "Nick Hornby"; //$NON-NLS-1$ + String press = "Penguin Books"; //$NON-NLS-1$ + double price = 21.30; + + Book book = createBook(id, title, author, press, price); + books.add(book); + } + + // save all + try (PersistenceTransaction tx = freshTx(ioMode);) { + ObjectDao objectDao = tx.getObjectDao(); + objectDao.addAll(books); + books.clear(); + } + + // query all + try (PersistenceTransaction tx = freshTx(ioMode);) { + TypeRef typeRef = tx.getObjectRefCache().getTypeRef(TestConstants.TYPE_BOOK); + ObjectDao objectDao = tx.getObjectDao(); + books = objectDao.queryAll(typeRef); + assertEquals("Expected to find 10 entries!", 10, books.size()); //$NON-NLS-1$ + + // delete them all + objectDao.removeAll(books); + } + + // now query them again + try (PersistenceTransaction tx = freshTx(ioMode);) { + TypeRef typeRef = tx.getObjectRefCache().getTypeRef(TestConstants.TYPE_BOOK); + ObjectDao objectDao = tx.getObjectDao(); + books = objectDao.queryAll(typeRef); + assertEquals("Expected to find 0 entries!", 0, books.size()); //$NON-NLS-1$ + } + } + + @Test + public void shouldPersistById() { + setup(IoMode.SAX); + + String classType = TestConstants.TYPE_BOOK; + long id = System.currentTimeMillis(); + String title = "About a boy"; //$NON-NLS-1$ + String author = "Nick Hornby"; //$NON-NLS-1$ + String press = "Penguin Books"; //$NON-NLS-1$ + double price = 21.30; + + // create a book + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + Book book = createBook(id, title, author, press, price); + tx.getObjectDao().add(book); + } + + // read by id + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + ObjectRef objectRef = tx.getObjectRefCache().getIdOfTypeRef(classType, Long.toString(id)); + Book book = tx.getObjectDao().queryById(objectRef); + assertNotNull("Expected to read book by ID", book); //$NON-NLS-1$ + } + + // delete by id + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + ObjectRef objectRef = tx.getObjectRefCache().getIdOfTypeRef(classType, Long.toString(id)); + tx.getObjectDao().removeById(objectRef); + } + + // fail to read by id + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + ObjectRef objectRef = tx.getObjectRefCache().getIdOfTypeRef(classType, Long.toString(id)); + Book book = tx.getObjectDao().queryById(objectRef); + assertNull("Expected that book was deleted by ID, thus can not be read anymore", book); //$NON-NLS-1$ + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/ObjectDaoResourceTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/ObjectDaoResourceTest.java new file mode 100644 index 000000000..5937b0e5e --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/ObjectDaoResourceTest.java @@ -0,0 +1,357 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import static li.strolch.xmlpers.test.impl.TestConstants.TYPE_RES; +import static li.strolch.xmlpers.test.model.ModelBuilder.RES_ID; +import static li.strolch.xmlpers.test.model.ModelBuilder.RES_TYPE; +import static li.strolch.xmlpers.test.model.ModelBuilder.assertResource; +import static li.strolch.xmlpers.test.model.ModelBuilder.assertResourceUpdated; +import static li.strolch.xmlpers.test.model.ModelBuilder.createResource; +import static li.strolch.xmlpers.test.model.ModelBuilder.updateResource; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.ObjectDao; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.api.XmlPersistenceException; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.SubTypeRef; +import li.strolch.xmlpers.test.impl.TestConstants; +import li.strolch.xmlpers.test.model.ModelBuilder; +import li.strolch.xmlpers.test.model.MyModel; + +/** + * @author Robert von Burg + * + */ +public class ObjectDaoResourceTest extends AbstractPersistenceTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private static final String BASEPATH = "target/db/ObjectDaoTest/"; //$NON-NLS-1$ + + @BeforeClass + public static void beforeClass() { + cleanPath(BASEPATH); + } + + private void setup(IoMode ioMode) { + Properties properties = new Properties(); + properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASEPATH + ioMode.name()); + setup(properties); + } + + @Test + public void testCrudSax() { + setup(IoMode.SAX); + testCrud(IoMode.SAX); + } + + @Test + public void testCrudDom() { + setup(IoMode.DOM); + testCrud(IoMode.DOM); + } + + private PersistenceTransaction freshTx(IoMode ioMode) { + PersistenceTransaction tx = this.persistenceManager.openTx(); + tx.setIoMode(ioMode); + return tx; + } + + private void testCrud(IoMode ioMode) { + + ObjectDao objectDao; + + // create new resource + MyModel resource = createResource(); + try (PersistenceTransaction tx = freshTx(ioMode);) { + objectDao = tx.getObjectDao(); + objectDao.add(resource); + } + + // read resource + try (PersistenceTransaction tx = freshTx(ioMode);) { + IdOfSubTypeRef resRef = tx.getObjectRefCache().getIdOfSubTypeRef(TestConstants.TYPE_RES, RES_TYPE, RES_ID); + objectDao = tx.getObjectDao(); + resource = objectDao.queryById(resRef); + assertResource(resource); + + // modify resource + updateResource(resource); + objectDao.update(resource); + } + + // read modified resource + try (PersistenceTransaction tx = freshTx(ioMode);) { + IdOfSubTypeRef resRef = tx.getObjectRefCache().getIdOfSubTypeRef(TestConstants.TYPE_RES, RES_TYPE, RES_ID); + objectDao = tx.getObjectDao(); + resource = objectDao.queryById(resRef); + assertResourceUpdated(resource); + } + + // delete resource + try (PersistenceTransaction tx = freshTx(ioMode);) { + objectDao = tx.getObjectDao(); + objectDao.remove(resource); + } + + // fail to read + try (PersistenceTransaction tx = freshTx(ioMode);) { + IdOfSubTypeRef resRef = tx.getObjectRefCache().getIdOfSubTypeRef(TestConstants.TYPE_RES, RES_TYPE, RES_ID); + objectDao = tx.getObjectDao(); + resource = objectDao.queryById(resRef); + assertNull(resource); + + // and create again + resource = createResource(); + assertResource(resource); + objectDao.add(resource); + } + } + + @Test + public void testBulkSax() { + setup(IoMode.SAX); + testBulk(IoMode.SAX); + } + + @Test + public void testBulkDom() { + setup(IoMode.DOM); + testBulk(IoMode.DOM); + } + + private void testBulk(IoMode ioMode) { + + // context + String type = "testBulk" + ioMode.name(); //$NON-NLS-1$ + + // create a list of resources + List resources = new ArrayList<>(10); + for (int i = 0; i < 10; i++) { + String id = RES_ID + "_" + i; //$NON-NLS-1$ + String name = "Bulk Test Object. " + i; //$NON-NLS-1$ + + MyModel resource = createResource(id, name, type); + resources.add(resource); + } + + // save all + try (PersistenceTransaction tx = freshTx(ioMode);) { + ObjectDao objectDao = tx.getObjectDao(); + objectDao.addAll(resources); + resources.clear(); + } + + // query all + try (PersistenceTransaction tx = freshTx(ioMode);) { + SubTypeRef subTypeRef = tx.getObjectRefCache().getSubTypeRef(TestConstants.TYPE_RES, type); + ObjectDao objectDao = tx.getObjectDao(); + resources = objectDao.queryAll(subTypeRef); + assertEquals("Expected to find 10 entries!", 10, resources.size()); //$NON-NLS-1$ + + // delete them all + objectDao.removeAll(resources); + } + + // now query them again + try (PersistenceTransaction tx = freshTx(ioMode);) { + SubTypeRef subTypeRef = tx.getObjectRefCache().getSubTypeRef(TestConstants.TYPE_RES, type); + ObjectDao objectDao = tx.getObjectDao(); + resources = objectDao.queryAll(subTypeRef); + assertEquals("Expected to find 0 entries!", 0, resources.size()); //$NON-NLS-1$ + } + } + + @Test + public void shouldPersistById() { + setup(IoMode.SAX); + + String classType = TestConstants.TYPE_RES; + String subType = ModelBuilder.RES_TYPE; + String id = "shouldPersistById"; //$NON-NLS-1$ + String name = "shouldPersistById "; //$NON-NLS-1$ + + // create a resource + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + MyModel resource = createResource(id, name, subType); + tx.getObjectDao().add(resource); + } + + // read by id + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(classType, subType, id); + MyModel resource = tx.getObjectDao().queryById(objectRef); + assertNotNull("Expected to read resource by ID", resource); //$NON-NLS-1$ + } + + // delete by id + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(classType, subType, id); + tx.getObjectDao().removeById(objectRef); + } + + // fail to read by id + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(classType, subType, id); + MyModel resource = tx.getObjectDao().queryById(objectRef); + assertNull("Expected that resource was deleted by ID, thus can not be read anymore", resource); //$NON-NLS-1$ + } + } + + @Test + public void shouldFailModifyNotExisting() { + setup(IoMode.SAX); + + this.thrown.expect(XmlPersistenceException.class); + this.thrown.expectMessage(containsString("Persistence unit does not exist for")); //$NON-NLS-1$ + + // update + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + MyModel resource = createResource(); + tx.getObjectDao().update(resource); + } + } + + @Test + public void shouldFailDeleteNotExisting() { + setup(IoMode.SAX); + + this.thrown.expect(XmlPersistenceException.class); + this.thrown.expectMessage(containsString("Persistence unit does not exist for")); //$NON-NLS-1$ + + // delete + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + MyModel resource = createResource(); + tx.getObjectDao().remove(resource); + } + } + + @Test + public void shouldAllowAllOperationsInSameTx() { + setup(IoMode.SAX); + + String subType = ModelBuilder.RES_TYPE; + String name = "shouldPersistById "; //$NON-NLS-1$ + + // create + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + String id = "shouldAllowAllOperationsInSameTx_create"; //$NON-NLS-1$ + MyModel resource = createResource(id, name, subType); + + tx.getObjectDao().add(resource); + } + + // create / modify + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + String id = "shouldAllowAllOperationsInSameTx_create_modify"; //$NON-NLS-1$ + MyModel resource = createResource(id, name, subType); + + tx.getObjectDao().add(resource); + tx.getObjectDao().update(resource); + } + + // create / delete + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + String id = "shouldAllowAllOperationsInSameTx_create_delete"; //$NON-NLS-1$ + MyModel resource = createResource(id, name, subType); + + tx.getObjectDao().add(resource); + tx.getObjectDao().remove(resource); + } + + // create / modify / delete + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + String id = "shouldAllowAllOperationsInSameTx_create_modify_delete"; //$NON-NLS-1$ + MyModel resource = createResource(id, name, subType); + + tx.getObjectDao().add(resource); + tx.getObjectDao().update(resource); + tx.getObjectDao().remove(resource); + } + + String id = "shouldAllowAllOperationsInSameTx_read_modify"; //$NON-NLS-1$ + + // prepare for read/modify + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + MyModel resource = createResource(id, name, subType); + tx.getObjectDao().add(resource); + } + + // read / modify + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id); + Object resource = tx.getObjectDao().queryById(objectRef); + assertNotNull(resource); + tx.getObjectDao().update(resource); + } + + // read / delete + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id); + Object resource = tx.getObjectDao().queryById(objectRef); + assertNotNull(resource); + tx.getObjectDao().remove(resource); + } + + // make sure deleted, then recreate + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id); + Object resource = tx.getObjectDao().queryById(objectRef); + assertNull(resource); + + // recreate + resource = createResource(id, name, subType); + tx.getObjectDao().add(resource); + } + + // read / modify / delete + try (PersistenceTransaction tx = this.persistenceManager.openTx()) { + + ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id); + Object resource = tx.getObjectDao().queryById(objectRef); + assertNotNull(resource); + tx.getObjectDao().update(resource); + tx.getObjectDao().remove(resource); + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/RealmTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/RealmTest.java new file mode 100644 index 000000000..d3689d406 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/RealmTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Properties; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.test.impl.TestConstants; +import li.strolch.xmlpers.test.model.ModelBuilder; +import li.strolch.xmlpers.test.model.MyModel; + +@SuppressWarnings("nls") +public class RealmTest extends AbstractPersistenceTest { + + private static final String REALM_2 = "Realm2"; + private static final String REALM_1 = "Realm1"; + protected static final String BASE_PATH = "target/db/RealmTest/"; + + @BeforeClass + public static void beforeClass() { + cleanPath(BASE_PATH); + } + + @Before + public void before() { + Properties properties = new Properties(); + properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASE_PATH + IoMode.DOM.name()); + setup(properties); + } + + @Test + public void shouldNotFindObjInBothRealms() { + + // object details + String objType = TestConstants.TYPE_RES; + String type = ModelBuilder.RES_TYPE; + String name = ModelBuilder.RES_NAME; + String id = "shouldNotFindObjInBothRealms"; + + // create in first realm + try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) { + MyModel resource1 = ModelBuilder.createResource(id, name, type); + txRealm1.getObjectDao().add(resource1); + } + + // find in first realm + try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) { + ObjectRef objectRef = txRealm1.getObjectRefCache().getIdOfSubTypeRef(objType, type, id); + MyModel resource = txRealm1.getObjectDao().queryById(objectRef); + assertNotNull("Resource was not found in first realm!", resource); + } + + // fail to find in second realm + try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) { + ObjectRef objectRef = txRealm2.getObjectRefCache().getIdOfSubTypeRef(objType, type, id); + MyModel resource = txRealm2.getObjectDao().queryById(objectRef); + assertNull("Resource was not created in second realm, thus not expected to be found there!", resource); + } + } + + @Test + public void shouldNotDeleteObjInWrongRealm() { + + // object details + String objType = TestConstants.TYPE_RES; + String subType = ModelBuilder.RES_TYPE; + String name = ModelBuilder.RES_NAME; + String id = "shouldNotDeleteObjInWrongRealm"; + + // create in first realm + try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) { + MyModel resource1 = ModelBuilder.createResource(id, name, subType); + txRealm1.getObjectDao().add(resource1); + } + + // create in second realm + try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) { + MyModel resource1 = ModelBuilder.createResource(id, name, subType); + txRealm2.getObjectDao().add(resource1); + } + + // delete in second realm + try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) { + ObjectRef objectRef = txRealm2.getObjectRefCache().getIdOfSubTypeRef(objType, subType, id); + txRealm2.getObjectDao().removeById(objectRef); + } + + // fail to find in second realm + try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) { + ObjectRef objectRef = txRealm2.getObjectRefCache().getIdOfSubTypeRef(objType, subType, id); + MyModel resource = txRealm2.getObjectDao().queryById(objectRef); + assertNull("Resource was not deleted from second realm, thus not expected to be found there!", resource); + } + + // find in first realm + try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) { + ObjectRef objectRef = txRealm1.getObjectRefCache().getIdOfSubTypeRef(objType, subType, id); + MyModel resource = txRealm1.getObjectDao().queryById(objectRef); + assertNotNull("Resource was not found in first realm!", resource); + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/TransactionResultTest.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/TransactionResultTest.java new file mode 100644 index 000000000..8d7c345dc --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/TransactionResultTest.java @@ -0,0 +1,135 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import static li.strolch.xmlpers.test.model.ModelBuilder.RES_ID; +import static li.strolch.xmlpers.test.model.ModelBuilder.createResource; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import li.strolch.xmlpers.api.IoMode; +import li.strolch.xmlpers.api.ModificationResult; +import li.strolch.xmlpers.api.ObjectDao; +import li.strolch.xmlpers.api.PersistenceConstants; +import li.strolch.xmlpers.api.PersistenceTransaction; +import li.strolch.xmlpers.api.TransactionResult; +import li.strolch.xmlpers.test.model.Book; +import li.strolch.xmlpers.test.model.MyModel; + +/** + * @author Robert von Burg + * + */ +public class TransactionResultTest extends AbstractPersistenceTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private static final String BASEPATH = "target/db/TxResultTest/"; //$NON-NLS-1$ + + @Before + public void setup() { + cleanPath(BASEPATH); + Properties properties = new Properties(); + properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASEPATH); + setup(properties); + } + + private PersistenceTransaction freshTx() { + PersistenceTransaction tx = this.persistenceManager.openTx(); + tx.setIoMode(IoMode.SAX); + return tx; + } + + @Test + public void testWithTxResult() { + + TransactionResult txResult = new TransactionResult(); + performChanges(txResult); + String logMessage = txResult.getLogMessage(); + logger.info(logMessage); + assertThat(logMessage, containsString("TX for realm defaultRealm was completed after")); //$NON-NLS-1$ + assertThat(logMessage, containsString("30 objects in 2 types were modified")); //$NON-NLS-1$ + assertThat(txResult.getKeys(), containsInAnyOrder("Resource", "Book")); //$NON-NLS-1$ //$NON-NLS-2$ + + ModificationResult resourceModificationResult = txResult.getModificationResult("Resource"); //$NON-NLS-1$ + assertEquals(20, resourceModificationResult.getCreated().size()); + assertEquals(0, resourceModificationResult.getUpdated().size()); + assertEquals(0, resourceModificationResult.getDeleted().size()); + + ModificationResult bookModificationResult = txResult.getModificationResult("Book"); //$NON-NLS-1$ + assertEquals(10, bookModificationResult.getCreated().size()); + assertEquals(0, bookModificationResult.getUpdated().size()); + assertEquals(0, bookModificationResult.getDeleted().size()); + } + + @Test + public void testWithoutTxResult() { + performChanges(null); + } + + private void performChanges(TransactionResult txResult) { + + // create a list of resources + List resources = new ArrayList<>(10); + int i = 0; + for (; i < 10; i++) { + String id = RES_ID + "_" + i; //$NON-NLS-1$ + String name = "Tx Result Test 1 Object. " + i; //$NON-NLS-1$ + String type = "testTxResult1"; //$NON-NLS-1$ + + MyModel resource = createResource(id, name, type); + resources.add(resource); + } + for (; i < 20; i++) { + String id = RES_ID + "_" + i; //$NON-NLS-1$ + String name = "Tx Result Test 2 Object. " + i; //$NON-NLS-1$ + String type = "testTxResult2"; //$NON-NLS-1$ + + MyModel resource = createResource(id, name, type); + resources.add(resource); + } + + // create a list of books + List books = new ArrayList<>(10); + i = 0; + for (; i < 10; i++) { + String title = "Tx Result Test Book " + i; //$NON-NLS-1$ + Book book = new Book((long) i, title, "Douglas Adams", "Apress", Math.random() * i); //$NON-NLS-1$ //$NON-NLS-2$ + books.add(book); + } + + // save all + try (PersistenceTransaction tx = freshTx();) { + tx.setTransactionResult(txResult); + ObjectDao objectDao = tx.getObjectDao(); + objectDao.addAll(resources); + objectDao.addAll(books); + resources.clear(); + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/XmlTestMain.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/XmlTestMain.java new file mode 100644 index 000000000..a68c9a8d8 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/XmlTestMain.java @@ -0,0 +1,297 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test; + +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; + +import javanet.staxutils.IndentingXMLStreamWriter; +import li.strolch.utils.exceptions.XmlException; +import li.strolch.utils.helper.XmlHelper; +import li.strolch.xmlpers.test.model.ModelBuilder; +import li.strolch.xmlpers.test.model.MyModel; +import li.strolch.xmlpers.test.model.MyParameter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * @author Robert von Burg + * + */ +@SuppressWarnings("nls") +public class XmlTestMain { + + private static final Logger logger = LoggerFactory.getLogger(XmlTestMain.class); + + private static MyModel res; + + public static void main(String[] args) throws Exception { + + res = ModelBuilder.createResource(); + + logger.info("Writing Res:\n" + res); + + writeSax(res); + writeDom(res); + + List resoures; + resoures = readDom(); + logger.info("Parsed Resources:\n" + resoures); + resoures = readSax(); + logger.info("Parsed Resources:\n" + resoures); + } + + /** + * @return + * + */ + private static List readDom() throws Exception { + + File file = new File("target/res_dom.xml"); + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + Document document = docBuilder.parse(file); + Element rootElement = document.getDocumentElement(); + + List resources = new ArrayList<>(); + + NodeList resElements = rootElement.getElementsByTagName("Resource"); + for (int i = 0; i < resElements.getLength(); i++) { + Element resElement = (Element) resElements.item(i); + String id = resElement.getAttribute("id"); + String name = resElement.getAttribute("name"); + String type = resElement.getAttribute("type"); + + MyModel res = new MyModel(); + res.setId(id); + res.setName(name); + res.setType(type); + + NodeList paramElements = resElement.getElementsByTagName("Parameter"); + parseParameters(res, paramElements); + + resources.add(res); + } + + logger.info("DOM parsed file " + file.getAbsolutePath()); + + return resources; + } + + private static void parseParameters(MyModel res, NodeList paramElements) { + for (int i = 0; i < paramElements.getLength(); i++) { + Element paramElement = (Element) paramElements.item(i); + String id = paramElement.getAttribute("id"); + String name = paramElement.getAttribute("name"); + String type = paramElement.getAttribute("type"); + String value = paramElement.getAttribute("value"); + + MyParameter param = new MyParameter(); + param.setId(id); + param.setName(name); + param.setType(type); + param.setValue(value); + + res.addParameter(param); + } + } + + /** + * @return + * + */ + private static List readSax() throws Exception { + + final List resources = new ArrayList<>(); + final MyModel[] currentRes = new MyModel[1]; + + DefaultHandler xmlHandler = new DefaultHandler() { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + + switch (qName) { + case "Resource": + MyModel res = new MyModel(); + res.setId(attributes.getValue("id")); + res.setName(attributes.getValue("name")); + res.setType(attributes.getValue("type")); + currentRes[0] = res; + resources.add(res); + break; + case "Parameter": + MyParameter param = new MyParameter(); + param.setId(attributes.getValue("id")); + param.setName(attributes.getValue("name")); + param.setType(attributes.getValue("type")); + param.setValue(attributes.getValue("value")); + currentRes[0].addParameter(param); + break; + case "model": + break; + default: + throw new IllegalArgumentException("The element '" + qName + "' is unhandled!"); + } + } + }; + + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser sp = spf.newSAXParser(); + File file = new File("target/res_sax.xml"); + sp.parse(file, xmlHandler); + + logger.info("SAX parsed file " + file.getAbsolutePath()); + + return resources; + } + + private static void writeDom(MyModel res) throws Exception { + + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Element resElement = doc.createElement("Resource"); + resElement.setAttribute("id", res.getId()); + resElement.setAttribute("name", res.getName()); + resElement.setAttribute("type", res.getType()); + + for (String paramId : res.getParameterKeySet()) { + MyParameter param = res.getParameterBy(paramId); + Element paramElement = doc.createElement("Parameter"); + paramElement.setAttribute("id", param.getId()); + paramElement.setAttribute("name", param.getName()); + paramElement.setAttribute("type", param.getType()); + paramElement.setAttribute("value", param.getValue()); + resElement.appendChild(paramElement); + } + + Element rootElement = doc.createElement("model"); + rootElement.appendChild(resElement); + + doc.appendChild(rootElement); + + String lineSep = System.getProperty(XmlHelper.PROP_LINE_SEPARATOR); + try { + + String encoding = doc.getInputEncoding(); + if (encoding == null || encoding.isEmpty()) { + logger.info("No encoding passed. Using default encoding " + XmlHelper.DEFAULT_ENCODING); + encoding = XmlHelper.DEFAULT_ENCODING; + } + + if (!lineSep.equals("\n")) { + logger.info("Overriding line separator to \\n"); + System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, "\n"); + } + + // Set up a transformer + TransformerFactory transfac = TransformerFactory.newInstance(); + Transformer transformer = transfac.newTransformer(); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.ENCODING, encoding); + transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); + // transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t"); + + // Transform to file + File file = new File("target/res_dom.xml"); + StreamResult result = new StreamResult(file); + Source xmlSource = new DOMSource(doc); + transformer.transform(xmlSource, result); + + logger.info("Wrote DOM to " + file.getAbsolutePath()); + + } catch (Exception e) { + + throw new XmlException("Exception while exporting to file: " + e, e); + + } finally { + + System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, lineSep); + } + } + + private static void writeSax(MyModel res) throws Exception { + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + + File file = new File("target/res_sax.xml"); + try (FileWriter fileWriter = new FileWriter(file)) { + XMLStreamWriter writer = factory.createXMLStreamWriter(fileWriter); + + writer = new IndentingXMLStreamWriter(writer); + + writer.writeStartDocument("utf-8", "1.0"); + writer.writeStartElement("model"); + + writer.writeStartElement("Resource"); + writer.writeAttribute("id", res.getId()); + writer.writeAttribute("name", res.getName()); + writer.writeAttribute("type", res.getType()); + + for (String paramId : res.getParameterKeySet()) { + MyParameter param = res.getParameterBy(paramId); + writer.writeEmptyElement("Parameter"); + writer.writeAttribute("id", param.getId()); + writer.writeAttribute("name", param.getName()); + writer.writeAttribute("type", param.getType()); + writer.writeAttribute("value", param.getValue()); + } + + //writer.writeEmptyElement("data"); + //writer.writeAttribute("name", "value"); + ////writer.writeEndElement(); + //writer.writeEmptyElement("stuff"); + //writer.writeAttribute("attr", "attrVal"); + + writer.writeEndElement(); + writer.writeEndDocument(); + + writer.flush(); + writer.close(); + logger.info("Wrote SAX to " + file.getAbsolutePath()); + + //Transformer transformer = TransformerFactory.newInstance().newTransformer(); + //Result outputTarget = new StaxR; + //Source xmlSource; + //transformer.transform(xmlSource, outputTarget); + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookContextFactory.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookContextFactory.java new file mode 100644 index 000000000..59b433bcb --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookContextFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.objref.IdOfTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.test.model.Book; + +public class BookContextFactory implements PersistenceContextFactory { + + @Override + public PersistenceContext createCtx(ObjectRef objectRef) { + PersistenceContext ctx = new PersistenceContext<>(objectRef); + ctx.setParserFactory(new BookParserFactory()); + return ctx; + } + + @Override + public PersistenceContext createCtx(ObjectReferenceCache objectRefCache, Book t) { + IdOfTypeRef objectRef = objectRefCache.getIdOfTypeRef(TestConstants.TYPE_BOOK, t.getId().toString()); + PersistenceContext ctx = createCtx(objectRef); + ctx.setObject(t); + return ctx; + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookDomParser.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookDomParser.java new file mode 100644 index 000000000..3e0fc1305 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookDomParser.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import javax.xml.parsers.DocumentBuilder; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.test.model.Book; +import li.strolch.xmlpers.util.DomUtil; + +/** + * @author Robert von Burg + * + */ +public class BookDomParser implements DomParser { + + private Book book; + + @Override + public Book getObject() { + return this.book; + } + + @Override + public void setObject(Book object) { + this.book = object; + } + + @SuppressWarnings("nls") + @Override + public Document toDom() { + + DocumentBuilder documentBuilder = DomUtil.createDocumentBuilder(); + Document document = documentBuilder.getDOMImplementation().createDocument(null, null, null); + + Element rootElement = document.createElement("Book"); + document.appendChild(rootElement); + rootElement.setAttribute("id", Long.toString(this.book.getId())); + rootElement.setAttribute("title", this.book.getTitle()); + rootElement.setAttribute("author", this.book.getAuthor()); + rootElement.setAttribute("press", this.book.getPress()); + rootElement.setAttribute("price", Double.toString(this.book.getPrice())); + + return document; + + } + + @SuppressWarnings("nls") + @Override + public void fromDom(Document document) { + + Element rootElement = document.getDocumentElement(); + + String idS = rootElement.getAttribute("id"); + long id = Long.parseLong(idS); + String title = rootElement.getAttribute("title"); + String author = rootElement.getAttribute("author"); + String press = rootElement.getAttribute("press"); + String priceS = rootElement.getAttribute("price"); + double price = Double.parseDouble(priceS); + + Book book = new Book(id, title, author, press, price); + this.book = book; + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookParserFactory.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookParserFactory.java new file mode 100644 index 000000000..de096413f --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookParserFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.api.ParserFactory; +import li.strolch.xmlpers.api.SaxParser; +import li.strolch.xmlpers.test.model.Book; + +/** + * @author Robert von Burg + * + */ +public class BookParserFactory implements ParserFactory { + + @Override + public DomParser getDomParser() { + return new BookDomParser(); + } + + @Override + public SaxParser getSaxParser() { + return new BookSaxParser(); + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookSaxParser.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookSaxParser.java new file mode 100644 index 000000000..7eb820839 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/BookSaxParser.java @@ -0,0 +1,85 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.xmlpers.api.SaxParser; +import li.strolch.xmlpers.test.model.Book; + +/** + * @author Robert von Burg + * + */ +public class BookSaxParser extends DefaultHandler implements SaxParser { + + private Book book; + + @Override + public Book getObject() { + return this.book; + } + + @Override + public void setObject(Book object) { + this.book = object; + + } + + @Override + public DefaultHandler getDefaultHandler() { + return this; + } + + @SuppressWarnings("nls") + @Override + public void write(XMLStreamWriter writer) throws XMLStreamException { + + writer.writeEmptyElement("Book"); + writer.writeAttribute("id", Long.toString(this.book.getId())); + writer.writeAttribute("title", this.book.getTitle()); + writer.writeAttribute("author", this.book.getAuthor()); + writer.writeAttribute("press", this.book.getPress()); + writer.writeAttribute("price", Double.toString(this.book.getPrice())); + } + + @SuppressWarnings("nls") + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + switch (qName) { + case "Book": + String idS = attributes.getValue("id"); + long id = Long.parseLong(idS); + Book book = new Book(id); + book.setTitle(attributes.getValue("title")); + book.setAuthor(attributes.getValue("author")); + book.setPress(attributes.getValue("press")); + String priceS = attributes.getValue("price"); + double price = Double.parseDouble(priceS); + book.setPrice(price); + this.book = book; + break; + default: + throw new IllegalArgumentException("The element '" + qName + "' is unhandled!"); + } + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelContextFactory.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelContextFactory.java new file mode 100644 index 000000000..860cfe5e6 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelContextFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import li.strolch.xmlpers.api.PersistenceContext; +import li.strolch.xmlpers.api.PersistenceContextFactory; +import li.strolch.xmlpers.objref.IdOfSubTypeRef; +import li.strolch.xmlpers.objref.ObjectRef; +import li.strolch.xmlpers.objref.ObjectReferenceCache; +import li.strolch.xmlpers.test.model.MyModel; + +public class MyModelContextFactory implements PersistenceContextFactory { + + @Override + public PersistenceContext createCtx(ObjectReferenceCache objectRefCache, MyModel t) { + IdOfSubTypeRef objectRef = objectRefCache.getIdOfSubTypeRef(TestConstants.TYPE_RES, t.getType(), t.getId()); + PersistenceContext ctx = createCtx(objectRef); + ctx.setObject(t); + return ctx; + } + + @Override + public PersistenceContext createCtx(ObjectRef objectRef) { + PersistenceContext ctx = new PersistenceContext<>(objectRef); + ctx.setParserFactory(new MyModelParserFactory()); + return ctx; + } + +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelDomParser.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelDomParser.java new file mode 100644 index 000000000..9fddf9fb0 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelDomParser.java @@ -0,0 +1,102 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import javax.xml.parsers.DocumentBuilder; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.test.model.MyModel; +import li.strolch.xmlpers.test.model.MyParameter; +import li.strolch.xmlpers.util.DomUtil; + +public class MyModelDomParser implements DomParser { + + private MyModel resource; + + @Override + public MyModel getObject() { + return this.resource; + } + + @Override + public void setObject(MyModel resource) { + this.resource = resource; + } + + @SuppressWarnings("nls") + @Override + public Document toDom() { + + DocumentBuilder documentBuilder = DomUtil.createDocumentBuilder(); + Document document = documentBuilder.getDOMImplementation().createDocument(null, null, null); + + Element element = document.createElement("Resource"); + document.appendChild(element); + + element.setAttribute("id", this.resource.getId()); + element.setAttribute("name", this.resource.getName()); + element.setAttribute("type", this.resource.getType()); + + for (String paramId : this.resource.getParameterKeySet()) { + MyParameter param = this.resource.getParameterBy(paramId); + Element paramElement = document.createElement("Parameter"); + element.appendChild(paramElement); + + paramElement.setAttribute("id", param.getId()); + paramElement.setAttribute("name", param.getName()); + paramElement.setAttribute("type", param.getType()); + paramElement.setAttribute("value", param.getValue()); + } + + return document; + } + + @SuppressWarnings("nls") + @Override + public void fromDom(Document document) { + + Element rootElement = document.getDocumentElement(); + + String id = rootElement.getAttribute("id"); + String name = rootElement.getAttribute("name"); + String type = rootElement.getAttribute("type"); + + MyModel resource = new MyModel(id, name, type); + + NodeList children = rootElement.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node item = children.item(i); + if (!item.getNodeName().equals("Parameter")) + continue; + + Element paramElement = (Element) item; + String paramId = paramElement.getAttribute("id"); + String paramName = paramElement.getAttribute("name"); + String paramType = paramElement.getAttribute("type"); + String paramValue = paramElement.getAttribute("value"); + + MyParameter param = new MyParameter(paramId, paramName, paramType, paramValue); + resource.addParameter(param); + } + + this.resource = resource; + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelParserFactory.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelParserFactory.java new file mode 100644 index 000000000..233473c31 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelParserFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import li.strolch.xmlpers.api.DomParser; +import li.strolch.xmlpers.api.ParserFactory; +import li.strolch.xmlpers.api.SaxParser; +import li.strolch.xmlpers.test.model.MyModel; + +public class MyModelParserFactory implements ParserFactory { + + @Override + public DomParser getDomParser() { + return new MyModelDomParser(); + } + + @Override + public SaxParser getSaxParser() { + return new MyModelSaxParser(); + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelSaxParser.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelSaxParser.java new file mode 100644 index 000000000..e4958d08e --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/MyModelSaxParser.java @@ -0,0 +1,91 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import li.strolch.xmlpers.api.SaxParser; +import li.strolch.xmlpers.test.model.MyModel; +import li.strolch.xmlpers.test.model.MyParameter; + +class MyModelSaxParser extends DefaultHandler implements SaxParser { + + private MyModel resource; + + @Override + public MyModel getObject() { + return this.resource; + } + + @Override + public void setObject(MyModel object) { + this.resource = object; + } + + @Override + public DefaultHandler getDefaultHandler() { + return this; + } + + @SuppressWarnings("nls") + @Override + public void write(XMLStreamWriter writer) throws XMLStreamException { + + writer.writeStartElement("Resource"); + writer.writeAttribute("id", this.resource.getId()); + writer.writeAttribute("name", this.resource.getName()); + writer.writeAttribute("type", this.resource.getType()); + for (String paramId : this.resource.getParameterKeySet()) { + MyParameter param = this.resource.getParameterBy(paramId); + writer.writeEmptyElement("Parameter"); + writer.writeAttribute("id", param.getId()); + writer.writeAttribute("name", param.getName()); + writer.writeAttribute("type", param.getType()); + writer.writeAttribute("value", param.getValue()); + } + writer.writeEndElement(); + } + + @SuppressWarnings("nls") + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + switch (qName) { + case "Resource": + String id = attributes.getValue("id"); + String name = attributes.getValue("name"); + String type = attributes.getValue("type"); + MyModel resource = new MyModel(id, name, type); + this.resource = resource; + break; + case "Parameter": + id = attributes.getValue("id"); + name = attributes.getValue("name"); + type = attributes.getValue("type"); + String value = attributes.getValue("value"); + MyParameter param = new MyParameter(id, name, type, value); + this.resource.addParameter(param); + break; + default: + throw new IllegalArgumentException("The element '" + qName + "' is unhandled!"); + } + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/TestConstants.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/TestConstants.java new file mode 100644 index 000000000..32d9ba515 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/impl/TestConstants.java @@ -0,0 +1,26 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.impl; + +/** + * @author Robert von Burg + * + */ +public class TestConstants { + + public static final String TYPE_RES = "Resource"; //$NON-NLS-1$ + public static final String TYPE_BOOK = "Book"; //$NON-NLS-1$ +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/Book.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/Book.java new file mode 100644 index 000000000..1b2ed7326 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/Book.java @@ -0,0 +1,121 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.model; + +/** + * @author Robert von Burg + * + */ +public class Book { + + private final Long id; + private String title; + private String author; + private String press; + private double price; + + /** + * @param id + * @param title + * @param author + * @param press + * @param price + */ + public Book(Long id, String title, String author, String press, double price) { + super(); + this.id = id; + this.title = title; + this.author = author; + this.press = press; + this.price = price; + } + + /** + * + */ + public Book(Long id) { + if (id == null) + throw new IllegalArgumentException("Id may not be null!"); //$NON-NLS-1$ + this.id = id; + } + + /** + * @return the id + */ + public Long getId() { + return this.id; + } + + /** + * @return the title + */ + public String getTitle() { + return this.title; + } + + /** + * @param title + * the title to set + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * @return the author + */ + public String getAuthor() { + return this.author; + } + + /** + * @param author + * the author to set + */ + public void setAuthor(String author) { + this.author = author; + } + + /** + * @return the press + */ + public String getPress() { + return this.press; + } + + /** + * @param press + * the press to set + */ + public void setPress(String press) { + this.press = press; + } + + /** + * @return the price + */ + public double getPrice() { + return this.price; + } + + /** + * @param price + * the price to set + */ + public void setPrice(double price) { + this.price = price; + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/ModelBuilder.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/ModelBuilder.java new file mode 100644 index 000000000..f30200e3d --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/ModelBuilder.java @@ -0,0 +1,123 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.model; + +import org.junit.Assert; + +/** + * @author Robert von Burg + * + */ +@SuppressWarnings("nls") +public class ModelBuilder { + + public static final String RES_TYPE = "@subType"; + public static final String RES_TYPE_INEXISTANT = "@inexistant"; + public static final String RES_NAME = "@name"; + public static final String RES_NAME_MODIFIED = "@name_modified"; + public static final String RES_ID = "@id"; + + public static final String PARAM_TYPE = "@paramType"; + public static final String PARAM_NAME = "@paramName"; + public static final String PARAM_ID = "@paramId"; + public static final String PARAM_VALUE_1 = "@paramValue1"; + public static final String PARAM_VALUE_2 = "@paramValue2"; + + public static final long BOOK_ID = 10L; + public static final String BOOK_TITLE = "Nick Hornby"; + public static final String BOOK_AUTHOR = "A long way down"; + public static final String BOOK_PRESS_1 = "Some press"; + public static final String BOOK_PRESS_2 = "Another press"; + public static final double BOOK_PRICE = 45.55D; + + public static MyModel createResource() { + return createResource(RES_ID, RES_NAME, RES_TYPE); + } + + public static MyModel createResource(String id) { + return createResource(id, RES_NAME, RES_TYPE); + } + + public static MyModel createResource(String id, String name, String type) { + MyModel resource = new MyModel(id, name, type); + MyParameter param = new MyParameter(PARAM_ID, PARAM_NAME, PARAM_TYPE, PARAM_VALUE_1); + resource.addParameter(param); + return resource; + } + + public static void updateResource(MyModel resource) { + resource.setName(RES_NAME_MODIFIED); + resource.getParameterBy(PARAM_ID).setValue(PARAM_VALUE_2); + } + + public static Book createBook() { + Book book = new Book(BOOK_ID, BOOK_TITLE, BOOK_AUTHOR, BOOK_PRESS_1, BOOK_PRICE); + return book; + } + + public static Book createBook(long id, String title, String author, String press, double price) { + Book book = new Book(id, title, author, press, price); + return book; + } + + public static void updateBook(Book book) { + book.setPress(BOOK_PRESS_2); + } + + public static void assertBook(Book book) { + Assert.assertNotNull(book); + Assert.assertEquals(BOOK_ID, book.getId().longValue()); + Assert.assertEquals(BOOK_TITLE, book.getTitle()); + Assert.assertEquals(BOOK_AUTHOR, book.getAuthor()); + Assert.assertEquals(BOOK_PRESS_1, book.getPress()); + Assert.assertEquals(BOOK_PRICE, book.getPrice(), 0.0); + } + + public static void assertBookUpdated(Book book) { + Assert.assertNotNull(book); + Assert.assertEquals(BOOK_ID, book.getId().longValue()); + Assert.assertEquals(BOOK_TITLE, book.getTitle()); + Assert.assertEquals(BOOK_AUTHOR, book.getAuthor()); + Assert.assertEquals(BOOK_PRESS_2, book.getPress()); + Assert.assertEquals(BOOK_PRICE, book.getPrice(), 0.0); + } + + public static void assertResource(MyModel resource) { + Assert.assertNotNull(resource); + Assert.assertEquals(RES_ID, resource.getId()); + Assert.assertEquals(RES_NAME, resource.getName()); + Assert.assertEquals(RES_TYPE, resource.getType()); + MyParameter param = resource.getParameterBy(PARAM_ID); + Assert.assertNotNull(param); + Assert.assertEquals(PARAM_ID, param.getId()); + Assert.assertEquals(PARAM_NAME, param.getName()); + Assert.assertEquals(PARAM_TYPE, param.getType()); + Assert.assertEquals(PARAM_VALUE_1, param.getValue()); + } + + public static void assertResourceUpdated(MyModel resource) { + Assert.assertNotNull(resource); + Assert.assertEquals(RES_ID, resource.getId()); + Assert.assertEquals(RES_NAME_MODIFIED, resource.getName()); + Assert.assertEquals(RES_TYPE, resource.getType()); + MyParameter param = resource.getParameterBy(PARAM_ID); + Assert.assertNotNull(param); + Assert.assertEquals(PARAM_ID, param.getId()); + Assert.assertEquals(PARAM_NAME, param.getName()); + Assert.assertEquals(PARAM_TYPE, param.getType()); + Assert.assertEquals(PARAM_VALUE_2, param.getValue()); + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/MyModel.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/MyModel.java new file mode 100644 index 000000000..7336ff11a --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/MyModel.java @@ -0,0 +1,124 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class MyModel { + + private String id; + private String name; + private String type; + private Map parameters = new HashMap<>(); + + /** + * + */ + public MyModel() { + // empty constructor + } + + /** + * @param id + * @param name + * @param type + */ + public MyModel(String id, String name, String type) { + super(); + this.id = id; + this.name = name; + this.type = type; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Resource [id="); + builder.append(this.id); + builder.append(", name="); + builder.append(this.name); + builder.append(", type="); + builder.append(this.type); + builder.append(", parameters="); + for (Entry param : this.parameters.entrySet()) { + builder.append("\n"); + builder.append(" " + param.getKey() + " = " + param.getValue()); + } + builder.append("]"); + return builder.toString(); + } + + /** + * @return the id + */ + public String getId() { + return this.id; + } + + /** + * @param id + * the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the name + */ + public String getName() { + return this.name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the type + */ + public String getType() { + return this.type; + } + + /** + * @param type + * the type to set + */ + public void setType(String type) { + this.type = type; + } + + public void addParameter(MyParameter parameter) { + this.parameters.put(parameter.getId(), parameter); + } + + public Set getParameterKeySet() { + return this.parameters.keySet(); + } + + public MyParameter getParameterBy(String id) { + return this.parameters.get(id); + } +} diff --git a/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/MyParameter.java b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/MyParameter.java new file mode 100644 index 000000000..ff5a7f5f3 --- /dev/null +++ b/li.strolch.xmlpers/src/test/java/li/strolch/xmlpers/test/model/MyParameter.java @@ -0,0 +1,121 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.xmlpers.test.model; + +public class MyParameter { + + private String id; + private String name; + private String type; + private String value; + + /** + * + */ + public MyParameter() { + // empty constructor + } + + /** + * @param id + * @param name + * @param type + * @param value + */ + public MyParameter(String id, String name, String type, String value) { + super(); + this.id = id; + this.name = name; + this.type = type; + this.value = value; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Parameter [id="); + builder.append(this.id); + builder.append(", name="); + builder.append(this.name); + builder.append(", type="); + builder.append(this.type); + builder.append(", value="); + builder.append(this.value); + builder.append("]"); + return builder.toString(); + } + + /** + * @return the id + */ + public String getId() { + return this.id; + } + + /** + * @param id + * the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the name + */ + public String getName() { + return this.name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the type + */ + public String getType() { + return this.type; + } + + /** + * @param type + * the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * @return the value + */ + public String getValue() { + return this.value; + } + + /** + * @param value + * the value to set + */ + public void setValue(String value) { + this.value = value; + } +} \ No newline at end of file diff --git a/li.strolch.xmlpers/src/test/resources/log4j.xml b/li.strolch.xmlpers/src/test/resources/log4j.xml new file mode 100644 index 000000000..216c8d616 --- /dev/null +++ b/li.strolch.xmlpers/src/test/resources/log4j.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 5bf824b69..1d18b44eb 100644 --- a/pom.xml +++ b/pom.xml @@ -1,52 +1,468 @@ - + 4.0.0 li.strolch li.strolch - 1.1.0-SNAPSHOT + 1.2.0-SNAPSHOT + li.strolch Module build for strolch pom - + http://www.strolch.li 2014 + + Github Issues + https://github.com/eitchnet/strolch/issues + + + + scm:git:https://github.com/eitchnet/strolch.git + scm:git:git@github.com:eitch/strolch.git + https://github.com/eitchnet/strolch + + + + + Apache License 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + + + + eitchnet.ch + http://www.strolch.li + + + + + eitch + Robert von Burg + eitch@eitchnet.ch + http://www.eitchnet.ch + eitchnet.ch + http://www.eitchnet.ch + + architect + developer + + +1 + + + - 1.1.0-SNAPSHOT - 1.1.0-SNAPSHOT - 1.1.0-SNAPSHOT - 1.1.0-SNAPSHOT UTF-8 yyyy-MM-dd HH:mm:ss ${maven.build.timestamp} + + 2.11 + + + li.strolch.privilege + li.strolch.utils + li.strolch.xmlpers + li.strolch.dev + li.strolch.bom + li.strolch.model + li.strolch.testbase + li.strolch.persistence.xml + li.strolch.persistence.postgresql + li.strolch.agent + li.strolch.service + li.strolch.rest + li.strolch.performancetest + li.strolch.tutorialapp + li.strolch.tutorialwebapp + li.strolch.planningwebapp + strolch_minimal + strolch_minimal_rest + + + + + + org.slf4j + slf4j-api + + + + + junit + junit + + + org.hamcrest + hamcrest-core + + + org.hamcrest + hamcrest-library + + + + + + + li.strolch + li.strolch.model + ${project.version} + + + li.strolch + li.strolch.agent + ${project.version} + + + li.strolch + li.strolch.service + ${project.version} + + + li.strolch + li.strolch.persistence.xml + ${project.version} + + + li.strolch + li.strolch.persistence.postgresql + ${project.version} + + + li.strolch + li.strolch.rest + ${project.version} + + + li.strolch + li.strolch.utils + ${project.version} + + + li.strolch + li.strolch.xmlpers + ${project.version} + + + li.strolch + li.strolch.privilege + ${project.version} + + + + + li.strolch + li.strolch.testbase + ${project.version} + test + + + + + org.slf4j + slf4j-api + 1.7.2 + + + commons-cli + commons-cli + 1.2 + + + com.github.petitparser.java-petitparser + petitparser-core + 2.0.2 + + + + + com.zaxxer + HikariCP + 2.3.6 + compile + + + org.postgresql + postgresql + 9.4.1208.jre7 + + + + + com.google.code.gson + gson + 2.3.1 + + + + + javax.mail + mail + 1.5.0-b01 + + + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + org.glassfish.jersey + jersey-bom + ${jersey.version} + pom + import + + + + + junit + junit + 4.11 + test + + + org.hamcrest + hamcrest-core + 1.3 + test + + + org.hamcrest + hamcrest-library + 1.3 + test + + + org.slf4j + slf4j-log4j12 + 1.7.2 + test + + + + + + + + src/main/resources + true + + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.2 + + + org.apache.maven.plugins + maven-scm-plugin + 1.9.4 + + ${project.artifactId}-${project.version} + + + + + org.codehaus.mojo + buildnumber-maven-plugin + 1.3 + + + validate + + create + + + + + false + false + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + true + true + -Xlint:all + + + + + org.apache.maven.plugins + maven-site-plugin + 3.4 + + UTF-8 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.10 + + true + true + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + attach-sources + package + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + + true + true + + + + + + + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + false + ${warFinalName} + + + + + org.apache.tomcat.maven + tomcat7-maven-plugin + 2.2 + + ${tomcat7Url} + ${tomcat7ServerId} + /${warFinalName} + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + attach-javadocs + deploy + + jar + + + + + -Xdoclint:none + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + deploy + deploy + + deploy + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + false + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.5.5 + + + + true + + + + + + + + + + + + + + + + + + + + + + - - jitpack.io snapshots @@ -61,34 +477,6 @@ - - archive.eitchnet.ch @@ -102,30 +490,4 @@ - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - - - - ch.eitchnet.parent - ch.eitchnet.privilege - ch.eitchnet.utils - ch.eitchnet.xmlpers - li.strolch.parent - li.strolch.dev - li.strolch.bom - li.strolch.model - li.strolch.testbase - li.strolch.persistence.xml - li.strolch.persistence.postgresql - li.strolch.agent - li.strolch.service - li.strolch.rest - li.strolch.performancetest - li.strolch.tutorialapp - li.strolch.tutorialwebapp - li.strolch.planningwebapp - diff --git a/strolch_minimal/pom.xml b/strolch_minimal/pom.xml index 2b925f3ee..5700b269e 100644 --- a/strolch_minimal/pom.xml +++ b/strolch_minimal/pom.xml @@ -1,13 +1,13 @@ - + 4.0.0 li.strolch strolch_minimal - 1.0.0-SNAPSHOT + 1.2.0-SNAPSHOT strolch_minimal Strolch app with minimal runtime - 2014 @@ -15,7 +15,7 @@ yyyy-MM-dd HH:mm:ss ${maven.build.timestamp} 1.8 - 1.1.0-SNAPSHOT + ${project.version} strolch_minimal diff --git a/strolch_minimal/src/main/java/li/strolch/minimal/main/Main.java b/strolch_minimal/src/main/java/li/strolch/minimal/main/Main.java index 225a0c3cb..a16a190ff 100644 --- a/strolch_minimal/src/main/java/li/strolch/minimal/main/Main.java +++ b/strolch_minimal/src/main/java/li/strolch/minimal/main/Main.java @@ -26,7 +26,7 @@ public class Main { * @param args */ public static void main(String[] args) { - MainStarter mainStarter = new MainStarter(); + MainStarter mainStarter = new MainStarter(Main.class); mainStarter.start(args); } } diff --git a/strolch_minimal/src/main/resources/log4j.xml b/strolch_minimal/src/main/resources/log4j.xml index 1d2f3b080..c886d766d 100644 --- a/strolch_minimal/src/main/resources/log4j.xml +++ b/strolch_minimal/src/main/resources/log4j.xml @@ -17,7 +17,7 @@ - + diff --git a/strolch_minimal/src/runtime/config/PrivilegeConfig.xml b/strolch_minimal/src/runtime/config/PrivilegeConfig.xml index e264a8929..14dc76906 100644 --- a/strolch_minimal/src/runtime/config/PrivilegeConfig.xml +++ b/strolch_minimal/src/runtime/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,7 +24,7 @@ - + \ No newline at end of file diff --git a/strolch_minimal/src/runtime/config/PrivilegeModel.xml b/strolch_minimal/src/runtime/config/PrivilegeModel.xml index 8132bbc46..69329b7c9 100644 --- a/strolch_minimal/src/runtime/config/PrivilegeModel.xml +++ b/strolch_minimal/src/runtime/config/PrivilegeModel.xml @@ -25,7 +25,7 @@ - + li.strolch.agent.impl.StartRealms diff --git a/strolch_minimal_rest/pom.xml b/strolch_minimal_rest/pom.xml index c5482f403..4212a0817 100644 --- a/strolch_minimal_rest/pom.xml +++ b/strolch_minimal_rest/pom.xml @@ -1,13 +1,12 @@ - + 4.0.0 li.strolch strolch_minimal_rest war - 1.0.0-SNAPSHOT - + 1.2.0-SNAPSHOT 2014 - strolch_minimal_rest http://www.strolch.li @@ -21,7 +20,7 @@ 1.8 - 1.1.0-SNAPSHOT + ${project.version} 2.11 2.0 @@ -69,12 +68,12 @@ - ch.eitchnet - ch.eitchnet.utils + li.strolch + li.strolch.utils - ch.eitchnet - ch.eitchnet.privilege + li.strolch + li.strolch.privilege @@ -99,7 +98,6 @@ javax.servlet javax.servlet-api - 3.0.1 provided @@ -113,11 +111,11 @@ jersey-container-grizzly2-http test - + com.google.code.gson gson - 2.3.1 diff --git a/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/main/StartupListener.java b/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/main/StartupListener.java index 2d3954935..51a2185ab 100644 --- a/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/main/StartupListener.java +++ b/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/main/StartupListener.java @@ -6,12 +6,13 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; -import li.strolch.agent.api.StrolchAgent; -import li.strolch.runtime.configuration.StrolchEnvironment; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import li.strolch.agent.api.StrolchAgent; +import li.strolch.agent.api.StrolchBootstrapper; +import li.strolch.runtime.configuration.StrolchEnvironment; + @WebListener public class StartupListener implements ServletContextListener { @@ -28,8 +29,7 @@ public class StartupListener implements ServletContextListener { String environment = StrolchEnvironment.getEnvironmentFromEnvProperties(pathF); logger.info("Starting Strolch Minimal Rest..."); try { - this.agent = new StrolchAgent(); - this.agent.setup(environment, pathF); + this.agent = new StrolchBootstrapper(StartupListener.class).setupByRoot(environment, pathF); this.agent.initialize(); this.agent.start(); } catch (Exception e) { diff --git a/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/util/Result.java b/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/util/Result.java index de5072134..f43d9d718 100644 --- a/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/util/Result.java +++ b/strolch_minimal_rest/src/main/java/li/strolch/minimal/rest/util/Result.java @@ -15,7 +15,7 @@ */ package li.strolch.minimal.rest.util; -import ch.eitchnet.utils.helper.StringHelper; +import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg diff --git a/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml b/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml index e264a8929..14dc76906 100644 --- a/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml +++ b/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeConfig.xml @@ -8,13 +8,13 @@ - + - + @@ -24,7 +24,7 @@ - + \ No newline at end of file diff --git a/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeModel.xml b/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeModel.xml index 8132bbc46..69329b7c9 100644 --- a/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeModel.xml +++ b/strolch_minimal_rest/src/main/webapp/WEB-INF/config/PrivilegeModel.xml @@ -25,7 +25,7 @@ - + li.strolch.agent.impl.StartRealms