diff --git a/ch.eitchnet.utils b/ch.eitchnet.utils index a67df72f3..cde6eb652 160000 --- a/ch.eitchnet.utils +++ b/ch.eitchnet.utils @@ -1 +1 @@ -Subproject commit a67df72f3f9b795796896889c2dbe1cf8561ccd2 +Subproject commit cde6eb652ec2c12ce22c8cb21a16589d56f8a49f diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java index 789c59808..8136efd81 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java @@ -15,14 +15,67 @@ */ package li.strolch.agent.api; +import java.util.concurrent.locks.Lock; + +import li.strolch.agent.impl.DefaultLockHandler; +import li.strolch.model.Locator; import li.strolch.model.StrolchRootElement; /** + *
+ * In Strolch locking of objects is done by keeping a lock for every {@link StrolchRootElement} by using the + * {@link Locator} to find the lock. Instead of adding a lock to the model, the lock is stored by the + * {@link LockHandler}. + *
+ * + *+ * Since new {@link StrolchRootElement} might not be known by the {@link ElementMap ElementMaps} but you still want to + * lock an object globally, then locking on the {@link Locator} solves this, as the locator is an immutable object and + * can easily be created before the actual object exists + *
+ * + *+ * See concrete implementations for which concrete locking implementation is used + *
+ * + * @see DefaultLockHandler + * * @author Robert von Burg+ * Unlocks the given element by finding the element's lock by its {@link Locator}. It is up to the concrete + * implementation to define if unlocking an unlocked element will fail or not. This method might not completely + * unlock the element if a lock counter is used and the object was locked multiple times. + *
+ * + *+ * If the lock must be completely released, then use {@link #releaseLock(StrolchRootElement)} + *
+ * + * @param element + * the element for which the current/last {@link Lock} is to be unlocked + */ public void unlock(StrolchRootElement element); + + /** + * Releases the lock on the given element, by unlocking all locks, i.e. after this method is called, no lock will be + * held anymore by the current thread + * + * @param element + * the element for which the {@link Lock} on the {@link Locator} is to be released + */ + public void releaseLock(StrolchRootElement element); } 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 8a811b256..1bfa6bc56 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 @@ -31,6 +31,8 @@ public interface StrolchRealm { public void unlock(StrolchRootElement lockedElement); + public void releaseLock(StrolchRootElement lockedElement); + public DataStoreMode getMode(); public StrolchTransaction openTx(Certificate certificate, Class> clazz); 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 e3ad62e59..bd2458f51 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 @@ -68,7 +68,7 @@ public class DefaultLockHandler implements LockHandler { this.lockMap.put(locator, lock); } - lock(this.tryLockTimeUnit, this.tryLockTime, lock); + lock(this.tryLockTimeUnit, this.tryLockTime, lock, element); } @Override @@ -82,15 +82,26 @@ public class DefaultLockHandler implements LockHandler { } } + @Override + public void releaseLock(StrolchRootElement element) { + Locator locator = element.getLocator(); + ReentrantLock lock = this.lockMap.get(locator); + if (lock == null || !lock.isHeldByCurrentThread()) { + logger.error(MessageFormat.format("Trying to unlock not locked element {0}", locator)); //$NON-NLS-1$ + } else { + releaseLock(lock); + } + } + /** * @see java.util.concurrent.locks.ReentrantLock#tryLock(long, TimeUnit) */ - private void lock(TimeUnit timeUnit, long tryLockTime, ReentrantLock lock) { + private void lock(TimeUnit timeUnit, long tryLockTime, ReentrantLock lock, StrolchRootElement element) { try { if (!lock.tryLock(tryLockTime, timeUnit)) { String msg = "Failed to acquire lock after {0}s for {1}"; //$NON-NLS-1$ - msg = MessageFormat.format(msg, timeUnit.toSeconds(tryLockTime), toString()); + msg = MessageFormat.format(msg, timeUnit.toSeconds(tryLockTime), element.getLocator()); throw new StrolchException(msg); } if (logger.isDebugEnabled()) @@ -108,4 +119,13 @@ public class DefaultLockHandler implements LockHandler { if (logger.isDebugEnabled()) logger.debug("unlocking " + toString()); //$NON-NLS-1$ } + + /** + * @see java.util.concurrent.locks.ReentrantLock#unlock() + */ + private void releaseLock(ReentrantLock lock) { + while (lock.isHeldByCurrentThread() && lock.isLocked()) { + unlock(lock); + } + } } 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 c5d975ddb..2cb64c8cd 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 @@ -77,13 +77,17 @@ public abstract class InternalStrolchRealm implements StrolchRealm { this.lockHandler.unlock(lockedElement); } + @Override + public void releaseLock(StrolchRootElement lockedElement) { + this.lockHandler.releaseLock(lockedElement); + } + public void initialize(ComponentContainer container, ComponentConfiguration configuration) { String propTryLockTimeUnit = StrolchConstants.makeRealmKey(this.realm, PROP_TRY_LOCK_TIME_UNIT); String propTryLockTime = StrolchConstants.makeRealmKey(this.realm, PROP_TRY_LOCK_TIME); - String enableAuditKey = StrolchConstants.makeRealmKey(getRealm(), - DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL); + String enableAuditKey = StrolchConstants.makeRealmKey(getRealm(), DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL); this.auditTrailEnabled = configuration.getBoolean(enableAuditKey, Boolean.FALSE); String enableAuditForReadKey = StrolchConstants.makeRealmKey(getRealm(), 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 5b73c4d35..21f4d601b 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 @@ -199,9 +199,9 @@ public abstract class AbstractTransaction implements StrolchTransaction { this.lockedElements.remove(element); } - private void unlockElements() { + private void releaseElementLocks() { for (StrolchRootElement lockedElement : this.lockedElements) { - this.realm.unlock(lockedElement); + this.realm.releaseLock(lockedElement); } } @@ -472,7 +472,7 @@ public abstract class AbstractTransaction implements StrolchTransaction { throw new StrolchPersistenceException(msg, e); } finally { - unlockElements(); + releaseElementLocks(); } } @@ -487,7 +487,7 @@ public abstract class AbstractTransaction implements StrolchTransaction { } catch (Exception e) { handleFailure(start, e); } finally { - unlockElements(); + releaseElementLocks(); } } @@ -510,19 +510,23 @@ public abstract class AbstractTransaction implements StrolchTransaction { StringBuilder sb = new StringBuilder(); sb.append("TX user="); sb.append(this.certificate.getUsername()); + sb.append(", action="); + sb.append(this.action); sb.append(", realm="); //$NON-NLS-1$ sb.append(getRealmName()); sb.append(", took="); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(txDuration)); - sb.append(", close="); //$NON-NLS-1$ - sb.append(StringHelper.formatNanoDuration(closeDuration)); - - if (isAuditTrailEnabled()) { + if (closeDuration >= 100000000L) { + sb.append(", close="); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(closeDuration)); + } + + if (isAuditTrailEnabled() && auditTrailDuration >= 100000000L) { sb.append(", auditTrail="); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(auditTrailDuration)); } - - if (isObserverUpdatesEnabled()) { + + if (isObserverUpdatesEnabled() && observerUpdateDuration >= 100000000L) { sb.append(", updates="); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(observerUpdateDuration)); } 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 25eb355c8..e0edc9637 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 @@ -65,7 +65,7 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class); this.certificateMap = new HashMap<>(); - this.sessionTimeoutTimer = new Timer("SessionTimeoutTimer"); //$NON-NLS-1$ + this.sessionTimeoutTimer = new Timer("SessionTimeoutTimer", true); //$NON-NLS-1$ long checkInterval = TimeUnit.MINUTES.toMillis(1); this.sessionTimeoutTimer.schedule(new SessionTimeoutTask(), checkInterval, checkInterval); 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 e3799a88e..d994503dd 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 @@ -132,8 +132,8 @@ public class RestfulStrolchComponent extends StrolchComponent { } // restful logging and tracing - this.restLogging = configuration.getBoolean(PARAM_REST_LOGGING, false); - this.restLoggingEntity = configuration.getBoolean(PARAM_REST_LOGGING_ENTITY, false); + this.restLogging = configuration.getBoolean(PARAM_REST_LOGGING, Boolean.FALSE); + this.restLoggingEntity = configuration.getBoolean(PARAM_REST_LOGGING_ENTITY, Boolean.FALSE); this.restTracing = configuration.getString(PARAM_REST_TRACING, "OFF"); //$NON-NLS-1$ this.restTracingThreshold = configuration.getString(PARAM_REST_TRACING_THRESHOLD, "TRACE"); //$NON-NLS-1$ 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 c188b73bd..695532515 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 @@ -121,33 +121,32 @@ public class AuthenticationService { @DELETE @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @Path("{authToken}") - public Response logout(@PathParam("authToken") String authToken) { + @Path("{sessionId}") + public Response logout(@PathParam("sessionId") String sessionId) { LogoutResult logoutResult = new LogoutResult(); - GenericEntity