Adapt after Argeo Suite refactoring.
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 14 Jan 2022 07:07:23 +0000 (08:07 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 14 Jan 2022 07:07:23 +0000 (08:07 +0100)
18 files changed:
org.argeo.cms.jcr/OSGI-INF/dataServletContext.xml
org.argeo.cms.jcr/OSGI-INF/filesServletContext.xml
org.argeo.cms.jcr/OSGI-INF/jcrDeployment.xml
org.argeo.cms.jcr/OSGI-INF/jcrServletContext.xml
org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/CmsJcrDeployment.java
org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/DataModels.java
org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/RepositoryContextsFactory.java
org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/DataServletContext.java [new file with mode: 0644]
org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/JcrServletContext.java [new file with mode: 0644]
org.argeo.cms.servlet/OSGI-INF/pkgServlet.xml
org.argeo.cms.servlet/src/org/argeo/cms/servlet/CmsServletContext.java
org.argeo.cms/src/org/argeo/cms/ArgeoLogListener.java
org.argeo.cms/src/org/argeo/cms/ArgeoLogger.java
org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsActivator.java
org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsOsgiLogger.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/osgi/GogoShellKiller.java
org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeLogger.java [deleted file]
org.argeo.init/src/org/argeo/init/logging/ThinLogging.java

index ffd8804b581f07303ded117712532208cd34f391..f5fc8deaa7ca6d0ea9690d3c14af7cd48f652b9f 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.dataServletContext">
-   <implementation class="org.argeo.cms.servlet.CmsServletContext"/>
+   <implementation class="org.argeo.cms.jcr.internal.servlet.DataServletContext"/>
    <service>
       <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
    </service>
index 049270c6a09827a97ef462fcd808959e56714a1d..5fb56e3ede4bbb74e11bc4ee573956718f5e267a 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.filesServletContext">
-   <implementation class="org.argeo.cms.servlet.PrivateWwwAuthServletContext"/>
+   <implementation class="org.argeo.cms.jcr.internal.servlet.JcrServletContext"/>
    <service>
       <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
    </service>
index fcba11cc555fe2cc5efcb7ba6797a9ebeeb17c93..a94b15168f483b05ea270c817f69ac04e3ccd0e9 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="JCR Deployment">
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" name="JCR Deployment">
    <implementation class="org.argeo.cms.jcr.internal.CmsJcrDeployment"/>
    <reference bind="setCmsDeployment" cardinality="1..1" interface="org.argeo.api.cms.CmsDeployment" policy="static"/>
 </scr:component>
index dd83c1d1c569fce1f99fa9ad580dcbd1c142f8fc..a0885bbc551edd23e5764ad0153c07d68a073bf8 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.jcrServletContext">
-   <implementation class="org.argeo.cms.servlet.PrivateWwwAuthServletContext"/>
+   <implementation class="org.argeo.cms.jcr.internal.servlet.JcrServletContext"/>
    <service>
       <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
    </service>
index 62899cdf688c87a5475659daa316ebe89c57d001..340d137824849b28917838e4aab5e43a15e378c1 100644 (file)
@@ -75,15 +75,15 @@ public class CmsJcrDeployment {
        CmsDeployment cmsDeployment;
 
        public CmsJcrDeployment() {
-               dataModels = new DataModels(bc);
 //             initTrackers();
        }
 
-       public void init() {
+       public void start() {
+               dataModels = new DataModels(bc);
 
                ServiceTracker<?, ?> repoContextSt = new RepositoryContextStc();
-               // repoContextSt.open();
-               KernelUtils.asyncOpen(repoContextSt);
+               repoContextSt.open();
+               //KernelUtils.asyncOpen(repoContextSt);
 
 //             nodeDeployment = CmsJcrActivator.getService(NodeDeployment.class);
 
@@ -91,7 +91,7 @@ public class CmsJcrDeployment {
 
        }
 
-       public void destroy() {
+       public void stop() {
 //             if (nodeHttp != null)
 //                     nodeHttp.destroy();
 
index 5a790f2ea648e52f49b628be916579954472769f..f2196bd41acb05915ba5496b68d968b1ad13d9e6 100644 (file)
@@ -9,7 +9,6 @@ import java.util.Map;
 import java.util.TreeMap;
 
 import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.CmsException;
 import org.argeo.cms.osgi.DataModelNamespace;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -129,7 +128,7 @@ class DataModels implements BundleListener {
                                assert requiredDataModelName != null;
                                DataModel requiredDataModel = dataModels.get(requiredDataModelName);
                                if (requiredDataModel == null)
-                                       throw new CmsException("No required data model " + requiredDataModelName);
+                                       throw new IllegalStateException("No required data model " + requiredDataModelName);
                                req.add(requiredDataModel);
                        }
                        required = Collections.unmodifiableList(req);
index 2b9ad0043f1b5731c42d11b498a4859167971564..2ffac9c4c9478dd2e24fd0d544605598147c5035 100644 (file)
@@ -38,10 +38,14 @@ public class RepositoryContextsFactory implements ManagedServiceFactory {
                for (String pid : repositories.keySet()) {
                        try {
                                RepositoryContext repositoryContext = repositories.get(pid);
-                               repositoryContext.getRepository().shutdown();
-                               if (log.isDebugEnabled())
-                                       log.debug("Shut down repository " + pid
-                                                       + (pidToCn.containsKey(pid) ? " (" + pidToCn.get(pid) + ")" : ""));
+                               // Must start in another thread otherwise shutdown is interrupted
+                               // TODO use an executor?
+                               new Thread(() -> {
+                                       repositoryContext.getRepository().shutdown();
+                                       if (log.isDebugEnabled())
+                                               log.debug("Shut down repository " + pid
+                                                               + (pidToCn.containsKey(pid) ? " (" + pidToCn.get(pid) + ")" : ""));
+                               }, "Shutdown JCR repository " + pid).start();
                        } catch (Exception e) {
                                log.error("Error when shutting down Jackrabbit repository " + pid, e);
                        }
diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/DataServletContext.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/DataServletContext.java
new file mode 100644 (file)
index 0000000..2f60e97
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms.jcr.internal.servlet;
+
+import org.argeo.cms.servlet.CmsServletContext;
+
+/** Internal subclass, so that config resources can be loaded from our bundle. */
+public class DataServletContext extends CmsServletContext {
+
+}
diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/JcrServletContext.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/internal/servlet/JcrServletContext.java
new file mode 100644 (file)
index 0000000..21046f3
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms.jcr.internal.servlet;
+
+import org.argeo.cms.servlet.PrivateWwwAuthServletContext;
+
+/** Internal subclass, so that config resources can be loaded from our bundle. */
+public class JcrServletContext extends PrivateWwwAuthServletContext {
+
+}
index 30e52311c10e2a15dc701d4efcb9abb2c66036b9..00fcaff99032147021a0271555bc70fa1d87dc6b 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.cms.pkgServlet">
-   <implementation class="org.argeo.cms.internal.http.PkgServlet"/>
+   <implementation class="org.argeo.cms.servlet.internal.PkgServlet"/>
    <service>
       <provide interface="javax.servlet.Servlet"/>
    </service>
index 40404c5d45d44eb70b675ee045acf2aee0674c1f..1ae6286ac2a4e38eb6c37bf4269c187a1d89a419 100644 (file)
@@ -90,6 +90,8 @@ public class CmsServletContext extends ServletContextHelper {
 
        @Override
        public URL getResource(String name) {
+               // TODO make it more robust and versatile
+               // if used directly it can only load from within this bundle
                return bundle.getResource(name);
        }
 
index e4a9941c77a49ad6c6d11b6d34b1727001e9d4f5..a01858aa99d243e8ce930a3cb6e102514fc0bc73 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.cms;
 
 /** Framework agnostic interface for log notifications */
+@Deprecated
 public interface ArgeoLogListener {
        /**
         * Appends a log
index 81a40f50c64db4abc05217b82951c8d6670b33c4..71c5039006212368fecf5c665e118d9abe8e097e 100644 (file)
@@ -4,6 +4,7 @@ package org.argeo.cms;
  * Logging framework agnostic identifying a logging service, to which one can
  * register
  */
+@Deprecated
 public interface ArgeoLogger {
        /**
         * Register for events by threads with the same authentication (or all
index 264f0c1b957729cb172b7bebae8b5fab1fae9c94..038d7029ca9cf6b720c1b8c01ef85e95384c32aa 100644 (file)
@@ -35,7 +35,7 @@ public class CmsActivator implements BundleActivator {
 
        private LogReaderService logReaderService;
 
-       private NodeLogger logger;
+       private CmsOsgiLogger logger;
 //     private CmsStateImpl nodeState;
 //     private CmsDeploymentImpl nodeDeployment;
 //     private CmsContextImpl nodeInstance;
@@ -55,6 +55,7 @@ public class CmsActivator implements BundleActivator {
 //             this.bc = bundleContext;
                if (bundleContext != null)
                        this.logReaderService = getService(LogReaderService.class);
+               initArgeoLogger();
 //             this.internalExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
 //
 //             try {
@@ -130,7 +131,7 @@ public class CmsActivator implements BundleActivator {
        }
 
        private void initArgeoLogger() {
-               logger = new NodeLogger(logReaderService);
+               logger = new CmsOsgiLogger(logReaderService);
                if (bundleContext != null)
                        bundleContext.registerService(ArgeoLogger.class, logger, null);
        }
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsOsgiLogger.java b/org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsOsgiLogger.java
new file mode 100644 (file)
index 0000000..91628d3
--- /dev/null
@@ -0,0 +1,541 @@
+package org.argeo.cms.internal.osgi;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.ArgeoLogListener;
+import org.argeo.cms.ArgeoLogger;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.internal.runtime.KernelConstants;
+import org.argeo.cms.internal.runtime.KernelUtils;
+import org.argeo.osgi.useradmin.UserAdminConf;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogLevel;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogReaderService;
+
+/** Not meant to be used directly in standard log4j config */
+public class CmsOsgiLogger implements ArgeoLogger, LogListener {
+       /** Internal debug for development purposes. */
+       private static Boolean debug = false;
+
+       private Boolean disabled = false;
+
+       private String level = null;
+
+//     private Level log4jLevel = null;
+
+       private Properties configuration;
+
+       private AppenderImpl appender;
+
+       private final List<ArgeoLogListener> everythingListeners = Collections
+                       .synchronizedList(new ArrayList<ArgeoLogListener>());
+       private final List<ArgeoLogListener> allUsersListeners = Collections
+                       .synchronizedList(new ArrayList<ArgeoLogListener>());
+       private final Map<String, List<ArgeoLogListener>> userListeners = Collections
+                       .synchronizedMap(new HashMap<String, List<ArgeoLogListener>>());
+
+       private BlockingQueue<LogEvent> events;
+       private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
+
+       private Integer maxLastEventsCount = 10 * 1000;
+
+       /** Marker to prevent stack overflow */
+       private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
+
+               @Override
+               protected Boolean initialValue() {
+                       return false;
+               }
+       };
+
+       public CmsOsgiLogger(LogReaderService lrs) {
+               if (lrs != null) {
+                       Enumeration<LogEntry> logEntries = lrs.getLog();
+                       while (logEntries.hasMoreElements())
+                               logged(logEntries.nextElement());
+                       lrs.addLogListener(this);
+
+                       // configure log4j watcher
+//                     String log4jConfiguration = KernelUtils.getFrameworkProp("log4j.configuration");
+//                     if (log4jConfiguration != null && log4jConfiguration.startsWith("file:")) {
+//                             if (log4jConfiguration.contains("..")) {
+//                                     if (log4jConfiguration.startsWith("file://"))
+//                                             log4jConfiguration = log4jConfiguration.substring("file://".length());
+//                                     else if (log4jConfiguration.startsWith("file:"))
+//                                             log4jConfiguration = log4jConfiguration.substring("file:".length());
+//                             }
+//                             try {
+//                                     Path log4jconfigPath;
+//                                     if (log4jConfiguration.startsWith("file:"))
+//                                             log4jconfigPath = Paths.get(new URI(log4jConfiguration));
+//                                     else
+//                                             log4jconfigPath = Paths.get(log4jConfiguration);
+//                                     Thread log4jConfWatcher = new Log4jConfWatcherThread(log4jconfigPath);
+//                                     log4jConfWatcher.start();
+//                             } catch (Exception e) {
+//                                     stdErr("Badly formatted log4j configuration URI " + log4jConfiguration + ": " + e.getMessage());
+//                             }
+//                     }
+               }
+       }
+
+       public void init() {
+               try {
+                       events = new LinkedBlockingQueue<LogEvent>();
+
+                       // if (layout != null)
+                       // setLayout(layout);
+                       // else
+                       // setLayout(new PatternLayout(pattern));
+                       appender = new AppenderImpl();
+                       reloadConfiguration();
+//                     Logger.getRootLogger().addAppender(appender);
+
+                       logDispatcherThread = new LogDispatcherThread();
+                       logDispatcherThread.start();
+               } catch (Exception e) {
+                       throw new CmsException("Cannot initialize log4j");
+               }
+       }
+
+       public void destroy() throws Exception {
+//             Logger.getRootLogger().removeAppender(appender);
+               allUsersListeners.clear();
+               for (List<ArgeoLogListener> lst : userListeners.values())
+                       lst.clear();
+               userListeners.clear();
+
+               events.clear();
+               events = null;
+               logDispatcherThread.interrupt();
+       }
+
+       // public void setLayout(Layout layout) {
+       // this.layout = layout;
+       // }
+
+       public String toString() {
+               return "Node Logger";
+       }
+
+       //
+       // OSGi LOGGER
+       //
+       @Override
+       public void logged(LogEntry status) {
+               CmsLog pluginLog = CmsLog.getLog(status.getBundle().getSymbolicName());
+               LogLevel severity = status.getLogLevel();
+               if (severity.equals(LogLevel.ERROR) && pluginLog.isErrorEnabled()) {
+                       // FIXME Fix Argeo TP
+                       if (status.getException() instanceof SignatureException)
+                               return;
+                       pluginLog.error(msg(status), status.getException());
+               } else if (severity.equals(LogLevel.WARN) && pluginLog.isWarnEnabled()) {
+                       if (pluginLog.isTraceEnabled())
+                               pluginLog.warn(msg(status), status.getException());
+                       else
+                               pluginLog.warn(msg(status));
+               } else if (severity.equals(LogLevel.INFO) && pluginLog.isDebugEnabled())
+                       pluginLog.debug(msg(status), status.getException());
+               else if (severity.equals(LogLevel.DEBUG) && pluginLog.isTraceEnabled())
+                       pluginLog.trace(msg(status), status.getException());
+               else if (severity.equals(LogLevel.TRACE) && pluginLog.isTraceEnabled())
+                       pluginLog.trace(msg(status), status.getException());
+       }
+
+       private String msg(LogEntry status) {
+               StringBuilder sb = new StringBuilder();
+               sb.append(status.getMessage());
+               Bundle bundle = status.getBundle();
+               if (bundle != null) {
+                       sb.append(" '" + bundle.getSymbolicName() + "'");
+               }
+               ServiceReference<?> sr = status.getServiceReference();
+               if (sr != null) {
+                       sb.append(' ');
+                       String[] objectClasses = (String[]) sr.getProperty(Constants.OBJECTCLASS);
+                       if (isSpringApplicationContext(objectClasses)) {
+                               sb.append("{org.springframework.context.ApplicationContext}");
+                               Object symbolicName = sr.getProperty(Constants.BUNDLE_SYMBOLICNAME);
+                               if (symbolicName != null)
+                                       sb.append(" " + Constants.BUNDLE_SYMBOLICNAME + ": " + symbolicName);
+                       } else {
+                               sb.append(arrayToString(objectClasses));
+                       }
+                       Object cn = sr.getProperty(CmsConstants.CN);
+                       if (cn != null)
+                               sb.append(" " + CmsConstants.CN + ": " + cn);
+                       Object factoryPid = sr.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);
+                       if (factoryPid != null)
+                               sb.append(" " + ConfigurationAdmin.SERVICE_FACTORYPID + ": " + factoryPid);
+                       // else {
+                       // Object servicePid = sr.getProperty(Constants.SERVICE_PID);
+                       // if (servicePid != null)
+                       // sb.append(" " + Constants.SERVICE_PID + ": " + servicePid);
+                       // }
+                       // servlets
+                       Object whiteBoardPattern = sr.getProperty(KernelConstants.WHITEBOARD_PATTERN_PROP);
+                       if (whiteBoardPattern != null) {
+                               if (whiteBoardPattern instanceof String) {
+                                       sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": " + whiteBoardPattern);
+                               } else {
+                                       sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": "
+                                                       + arrayToString((String[]) whiteBoardPattern));
+                               }
+                       }
+                       // RWT
+                       Object contextName = sr.getProperty(KernelConstants.CONTEXT_NAME_PROP);
+                       if (contextName != null)
+                               sb.append(" " + KernelConstants.CONTEXT_NAME_PROP + ": " + contextName);
+
+                       // user directories
+                       Object baseDn = sr.getProperty(UserAdminConf.baseDn.name());
+                       if (baseDn != null)
+                               sb.append(" " + UserAdminConf.baseDn.name() + ": " + baseDn);
+
+               }
+               return sb.toString();
+       }
+
+       private String arrayToString(Object[] arr) {
+               StringBuilder sb = new StringBuilder();
+               sb.append('[');
+               for (int i = 0; i < arr.length; i++) {
+                       if (i != 0)
+                               sb.append(',');
+                       sb.append(arr[i]);
+               }
+               sb.append(']');
+               return sb.toString();
+       }
+
+       private boolean isSpringApplicationContext(String[] objectClasses) {
+               for (String clss : objectClasses) {
+                       if (clss.equals("org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext")) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       //
+       // ARGEO LOGGER
+       //
+
+       public synchronized void register(ArgeoLogListener listener, Integer numberOfPreviousEvents) {
+               String username = CurrentUser.getUsername();
+               if (username == null)
+                       throw new CmsException("Only authenticated users can register a log listener");
+
+               if (!userListeners.containsKey(username)) {
+                       List<ArgeoLogListener> lst = Collections.synchronizedList(new ArrayList<ArgeoLogListener>());
+                       userListeners.put(username, lst);
+               }
+               userListeners.get(username).add(listener);
+               List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username, numberOfPreviousEvents);
+               for (LogEvent evt : lastEvents)
+                       dispatchEvent(listener, evt);
+       }
+
+       public synchronized void registerForAll(ArgeoLogListener listener, Integer numberOfPreviousEvents,
+                       boolean everything) {
+               if (everything)
+                       everythingListeners.add(listener);
+               else
+                       allUsersListeners.add(listener);
+               List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null, numberOfPreviousEvents);
+               for (LogEvent evt : lastEvents)
+                       if (everything || evt.getUsername() != null)
+                               dispatchEvent(listener, evt);
+       }
+
+       public synchronized void unregister(ArgeoLogListener listener) {
+               String username = CurrentUser.getUsername();
+               if (username == null)// FIXME
+                       return;
+               if (!userListeners.containsKey(username))
+                       throw new IllegalStateException("No user listeners " + listener + " registered for user " + username);
+               if (!userListeners.get(username).contains(listener))
+                       throw new IllegalStateException("No user listeners " + listener + " registered for user " + username);
+               userListeners.get(username).remove(listener);
+               if (userListeners.get(username).isEmpty())
+                       userListeners.remove(username);
+
+       }
+
+       public synchronized void unregisterForAll(ArgeoLogListener listener) {
+               everythingListeners.remove(listener);
+               allUsersListeners.remove(listener);
+       }
+
+       /** For development purpose, since using regular logging is not easy here */
+       private static void stdOut(Object obj) {
+               System.out.println(obj);
+       }
+
+       private static void stdErr(Object obj) {
+               System.err.println(obj);
+       }
+
+       private static void debug(Object obj) {
+               if (debug)
+                       System.out.println(obj);
+       }
+
+       private static boolean isInternalDebugEnabled() {
+               return debug;
+       }
+
+       // public void setPattern(String pattern) {
+       // this.pattern = pattern;
+       // }
+
+       public void setDisabled(Boolean disabled) {
+               this.disabled = disabled;
+       }
+
+       public void setLevel(String level) {
+               this.level = level;
+       }
+
+       public void setConfiguration(Properties configuration) {
+               this.configuration = configuration;
+       }
+
+       public void updateConfiguration(Properties configuration) {
+               setConfiguration(configuration);
+               reloadConfiguration();
+       }
+
+       public Properties getConfiguration() {
+               return configuration;
+       }
+
+       /**
+        * Reloads configuration (if the configuration {@link Properties} is set)
+        */
+       protected void reloadConfiguration() {
+               if (configuration != null) {
+//                     LogManager.resetConfiguration();
+//                     PropertyConfigurator.configure(configuration);
+               }
+       }
+
+       protected synchronized void processLoggingEvent(LogEvent event) {
+               if (disabled)
+                       return;
+
+               if (dispatching.get())
+                       return;
+
+               if (level != null && !level.trim().equals("")) {
+//                     if (log4jLevel == null || !log4jLevel.toString().equals(level))
+//                             try {
+//                                     log4jLevel = Level.toLevel(level);
+//                             } catch (Exception e) {
+//                                     System.err.println("Log4j level could not be set for level '" + level + "', resetting it to null.");
+//                                     e.printStackTrace();
+//                                     level = null;
+//                             }
+//
+//                     if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
+//                             return;
+//                     }
+               }
+
+               try {
+                       // admin listeners
+                       Iterator<ArgeoLogListener> everythingIt = everythingListeners.iterator();
+                       while (everythingIt.hasNext())
+                               dispatchEvent(everythingIt.next(), event);
+
+                       if (event.getUsername() != null) {
+                               Iterator<ArgeoLogListener> allUsersIt = allUsersListeners.iterator();
+                               while (allUsersIt.hasNext())
+                                       dispatchEvent(allUsersIt.next(), event);
+
+                               if (userListeners.containsKey(event.getUsername())) {
+                                       Iterator<ArgeoLogListener> userIt = userListeners.get(event.getUsername()).iterator();
+                                       while (userIt.hasNext())
+                                               dispatchEvent(userIt.next(), event);
+                               }
+                       }
+               } catch (Exception e) {
+                       stdOut("Cannot process logging event");
+                       e.printStackTrace();
+               }
+       }
+
+       protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
+//             LoggingEvent event = evt.getLoggingEvent();
+//             logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event.getLevel().toString(),
+//                             event.getLoggerName(), event.getThreadName(), event.getMessage(), event.getThrowableStrRep());
+       }
+
+       private class AppenderImpl { //extends AppenderSkeleton {
+               public boolean requiresLayout() {
+                       return false;
+               }
+
+               public void close() {
+               }
+
+//             @Override
+//             protected void append(LoggingEvent event) {
+//                     if (events != null) {
+//                             try {
+//                                     String username = CurrentUser.getUsername();
+//                                     events.put(new LogEvent(username, event));
+//                             } catch (InterruptedException e) {
+//                                     // silent
+//                             }
+//                     }
+//             }
+
+       }
+
+       private class LogDispatcherThread extends Thread {
+               /** encapsulated in order to simplify concurrency management */
+               private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
+
+               public LogDispatcherThread() {
+                       super("Argeo Logging Dispatcher Thread");
+               }
+
+               public void run() {
+                       while (events != null) {
+                               try {
+                                       LogEvent loggingEvent = events.take();
+                                       processLoggingEvent(loggingEvent);
+                                       addLastEvent(loggingEvent);
+                               } catch (InterruptedException e) {
+                                       if (events == null)
+                                               return;
+                               }
+                       }
+               }
+
+               protected synchronized void addLastEvent(LogEvent loggingEvent) {
+                       if (lastEvents.size() >= maxLastEventsCount)
+                               lastEvents.poll();
+                       lastEvents.add(loggingEvent);
+               }
+
+               public synchronized List<LogEvent> getLastEvents(String username, Integer maxCount) {
+                       LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
+                       ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents.size());
+                       int count = 0;
+                       while (it.hasPrevious() && (count < maxCount)) {
+                               LogEvent evt = it.previous();
+                               if (username == null || username.equals(evt.getUsername())) {
+                                       evts.push(evt);
+                                       count++;
+                               }
+                       }
+                       return evts;
+               }
+       }
+
+       private class LogEvent {
+               private final String username;
+//             private final LoggingEvent loggingEvent;
+
+               public LogEvent(String username) {
+                       super();
+                       this.username = username;
+//                     this.loggingEvent = loggingEvent;
+               }
+
+//             @Override
+//             public int hashCode() {
+//                     return loggingEvent.hashCode();
+//             }
+//
+//             @Override
+//             public boolean equals(Object obj) {
+//                     return loggingEvent.equals(obj);
+//             }
+//
+//             @Override
+//             public String toString() {
+//                     return username + "@ " + loggingEvent.toString();
+//             }
+
+               public String getUsername() {
+                       return username;
+               }
+
+//             public LoggingEvent getLoggingEvent() {
+//                     return loggingEvent;
+//             }
+
+       }
+
+       private class Log4jConfWatcherThread extends Thread {
+               private Path log4jConfigurationPath;
+
+               public Log4jConfWatcherThread(Path log4jConfigurationPath) {
+                       super("Log4j Configuration Watcher");
+                       try {
+                               this.log4jConfigurationPath = log4jConfigurationPath.toRealPath();
+                       } catch (IOException e) {
+                               this.log4jConfigurationPath = log4jConfigurationPath.toAbsolutePath();
+                               stdOut("Cannot determine real path for " + log4jConfigurationPath + ": " + e.getMessage());
+                       }
+               }
+
+               public void run() {
+                       Path parentDir = log4jConfigurationPath.getParent();
+                       try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
+                               parentDir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
+                               WatchKey wk;
+                               watching: while ((wk = watchService.take()) != null) {
+                                       for (WatchEvent<?> event : wk.pollEvents()) {
+                                               final Path changed = (Path) event.context();
+                                               if (log4jConfigurationPath.equals(parentDir.resolve(changed))) {
+                                                       if (isInternalDebugEnabled())
+                                                               debug(log4jConfigurationPath + " has changed, reloading.");
+//                                                     PropertyConfigurator.configure(log4jConfigurationPath.toUri().toURL());
+                                               }
+                                       }
+                                       // reset the key
+                                       boolean valid = wk.reset();
+                                       if (!valid) {
+                                               break watching;
+                                       }
+                               }
+                       } catch (IOException | InterruptedException e) {
+                               stdErr("Log4j configuration watcher failed: " + e.getMessage());
+                       }
+               }
+       }
+}
index 85c686a0a8392e9a8bd7e5a39b044d1f5634f24b..a8c901644b13e21cb9d63f565efac5832c35d1ea 100644 (file)
@@ -1,7 +1,5 @@
 package org.argeo.cms.internal.osgi;
 
-import java.io.IOException;
-
 /**
  * Workaround for killing Gogo shell by system shutdown.
  * 
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeLogger.java b/org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeLogger.java
deleted file mode 100644 (file)
index 69dbec9..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-package org.argeo.cms.internal.osgi;
-
-import java.io.IOException;
-import java.net.URI;
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardWatchEventKinds;
-import java.nio.file.WatchEvent;
-import java.nio.file.WatchKey;
-import java.nio.file.WatchService;
-import java.security.SignatureException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.ArgeoLogListener;
-import org.argeo.cms.ArgeoLogger;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.internal.runtime.KernelConstants;
-import org.argeo.cms.internal.runtime.KernelUtils;
-import org.argeo.osgi.useradmin.UserAdminConf;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.log.LogEntry;
-import org.osgi.service.log.LogLevel;
-import org.osgi.service.log.LogListener;
-import org.osgi.service.log.LogReaderService;
-
-/** Not meant to be used directly in standard log4j config */
-public class NodeLogger implements ArgeoLogger, LogListener {
-       /** Internal debug for development purposes. */
-       private static Boolean debug = false;
-
-       private Boolean disabled = false;
-
-       private String level = null;
-
-//     private Level log4jLevel = null;
-
-       private Properties configuration;
-
-       private AppenderImpl appender;
-
-       private final List<ArgeoLogListener> everythingListeners = Collections
-                       .synchronizedList(new ArrayList<ArgeoLogListener>());
-       private final List<ArgeoLogListener> allUsersListeners = Collections
-                       .synchronizedList(new ArrayList<ArgeoLogListener>());
-       private final Map<String, List<ArgeoLogListener>> userListeners = Collections
-                       .synchronizedMap(new HashMap<String, List<ArgeoLogListener>>());
-
-       private BlockingQueue<LogEvent> events;
-       private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
-
-       private Integer maxLastEventsCount = 10 * 1000;
-
-       /** Marker to prevent stack overflow */
-       private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
-
-               @Override
-               protected Boolean initialValue() {
-                       return false;
-               }
-       };
-
-       public NodeLogger(LogReaderService lrs) {
-               if (lrs != null) {
-                       Enumeration<LogEntry> logEntries = lrs.getLog();
-                       while (logEntries.hasMoreElements())
-                               logged(logEntries.nextElement());
-                       lrs.addLogListener(this);
-
-                       // configure log4j watcher
-                       String log4jConfiguration = KernelUtils.getFrameworkProp("log4j.configuration");
-                       if (log4jConfiguration != null && log4jConfiguration.startsWith("file:")) {
-                               if (log4jConfiguration.contains("..")) {
-                                       if (log4jConfiguration.startsWith("file://"))
-                                               log4jConfiguration = log4jConfiguration.substring("file://".length());
-                                       else if (log4jConfiguration.startsWith("file:"))
-                                               log4jConfiguration = log4jConfiguration.substring("file:".length());
-                               }
-                               try {
-                                       Path log4jconfigPath;
-                                       if (log4jConfiguration.startsWith("file:"))
-                                               log4jconfigPath = Paths.get(new URI(log4jConfiguration));
-                                       else
-                                               log4jconfigPath = Paths.get(log4jConfiguration);
-                                       Thread log4jConfWatcher = new Log4jConfWatcherThread(log4jconfigPath);
-                                       log4jConfWatcher.start();
-                               } catch (Exception e) {
-                                       stdErr("Badly formatted log4j configuration URI " + log4jConfiguration + ": " + e.getMessage());
-                               }
-                       }
-               }
-       }
-
-       public void init() {
-               try {
-                       events = new LinkedBlockingQueue<LogEvent>();
-
-                       // if (layout != null)
-                       // setLayout(layout);
-                       // else
-                       // setLayout(new PatternLayout(pattern));
-                       appender = new AppenderImpl();
-                       reloadConfiguration();
-//                     Logger.getRootLogger().addAppender(appender);
-
-                       logDispatcherThread = new LogDispatcherThread();
-                       logDispatcherThread.start();
-               } catch (Exception e) {
-                       throw new CmsException("Cannot initialize log4j");
-               }
-       }
-
-       public void destroy() throws Exception {
-//             Logger.getRootLogger().removeAppender(appender);
-               allUsersListeners.clear();
-               for (List<ArgeoLogListener> lst : userListeners.values())
-                       lst.clear();
-               userListeners.clear();
-
-               events.clear();
-               events = null;
-               logDispatcherThread.interrupt();
-       }
-
-       // public void setLayout(Layout layout) {
-       // this.layout = layout;
-       // }
-
-       public String toString() {
-               return "Node Logger";
-       }
-
-       //
-       // OSGi LOGGER
-       //
-       @Override
-       public void logged(LogEntry status) {
-               CmsLog pluginLog = CmsLog.getLog(status.getBundle().getSymbolicName());
-               LogLevel severity = status.getLogLevel();
-               if (severity.equals(LogLevel.ERROR) && pluginLog.isErrorEnabled()) {
-                       // FIXME Fix Argeo TP
-                       if (status.getException() instanceof SignatureException)
-                               return;
-                       pluginLog.error(msg(status), status.getException());
-               } else if (severity.equals(LogLevel.WARN) && pluginLog.isWarnEnabled()) {
-                       if (pluginLog.isTraceEnabled())
-                               pluginLog.warn(msg(status), status.getException());
-                       else
-                               pluginLog.warn(msg(status));
-               } else if (severity.equals(LogLevel.INFO) && pluginLog.isDebugEnabled())
-                       pluginLog.debug(msg(status), status.getException());
-               else if (severity.equals(LogLevel.DEBUG) && pluginLog.isTraceEnabled())
-                       pluginLog.trace(msg(status), status.getException());
-               else if (severity.equals(LogLevel.TRACE) && pluginLog.isTraceEnabled())
-                       pluginLog.trace(msg(status), status.getException());
-       }
-
-       private String msg(LogEntry status) {
-               StringBuilder sb = new StringBuilder();
-               sb.append(status.getMessage());
-               Bundle bundle = status.getBundle();
-               if (bundle != null) {
-                       sb.append(" '" + bundle.getSymbolicName() + "'");
-               }
-               ServiceReference<?> sr = status.getServiceReference();
-               if (sr != null) {
-                       sb.append(' ');
-                       String[] objectClasses = (String[]) sr.getProperty(Constants.OBJECTCLASS);
-                       if (isSpringApplicationContext(objectClasses)) {
-                               sb.append("{org.springframework.context.ApplicationContext}");
-                               Object symbolicName = sr.getProperty(Constants.BUNDLE_SYMBOLICNAME);
-                               if (symbolicName != null)
-                                       sb.append(" " + Constants.BUNDLE_SYMBOLICNAME + ": " + symbolicName);
-                       } else {
-                               sb.append(arrayToString(objectClasses));
-                       }
-                       Object cn = sr.getProperty(CmsConstants.CN);
-                       if (cn != null)
-                               sb.append(" " + CmsConstants.CN + ": " + cn);
-                       Object factoryPid = sr.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);
-                       if (factoryPid != null)
-                               sb.append(" " + ConfigurationAdmin.SERVICE_FACTORYPID + ": " + factoryPid);
-                       // else {
-                       // Object servicePid = sr.getProperty(Constants.SERVICE_PID);
-                       // if (servicePid != null)
-                       // sb.append(" " + Constants.SERVICE_PID + ": " + servicePid);
-                       // }
-                       // servlets
-                       Object whiteBoardPattern = sr.getProperty(KernelConstants.WHITEBOARD_PATTERN_PROP);
-                       if (whiteBoardPattern != null) {
-                               if (whiteBoardPattern instanceof String) {
-                                       sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": " + whiteBoardPattern);
-                               } else {
-                                       sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": "
-                                                       + arrayToString((String[]) whiteBoardPattern));
-                               }
-                       }
-                       // RWT
-                       Object contextName = sr.getProperty(KernelConstants.CONTEXT_NAME_PROP);
-                       if (contextName != null)
-                               sb.append(" " + KernelConstants.CONTEXT_NAME_PROP + ": " + contextName);
-
-                       // user directories
-                       Object baseDn = sr.getProperty(UserAdminConf.baseDn.name());
-                       if (baseDn != null)
-                               sb.append(" " + UserAdminConf.baseDn.name() + ": " + baseDn);
-
-               }
-               return sb.toString();
-       }
-
-       private String arrayToString(Object[] arr) {
-               StringBuilder sb = new StringBuilder();
-               sb.append('[');
-               for (int i = 0; i < arr.length; i++) {
-                       if (i != 0)
-                               sb.append(',');
-                       sb.append(arr[i]);
-               }
-               sb.append(']');
-               return sb.toString();
-       }
-
-       private boolean isSpringApplicationContext(String[] objectClasses) {
-               for (String clss : objectClasses) {
-                       if (clss.equals("org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext")) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       //
-       // ARGEO LOGGER
-       //
-
-       public synchronized void register(ArgeoLogListener listener, Integer numberOfPreviousEvents) {
-               String username = CurrentUser.getUsername();
-               if (username == null)
-                       throw new CmsException("Only authenticated users can register a log listener");
-
-               if (!userListeners.containsKey(username)) {
-                       List<ArgeoLogListener> lst = Collections.synchronizedList(new ArrayList<ArgeoLogListener>());
-                       userListeners.put(username, lst);
-               }
-               userListeners.get(username).add(listener);
-               List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username, numberOfPreviousEvents);
-               for (LogEvent evt : lastEvents)
-                       dispatchEvent(listener, evt);
-       }
-
-       public synchronized void registerForAll(ArgeoLogListener listener, Integer numberOfPreviousEvents,
-                       boolean everything) {
-               if (everything)
-                       everythingListeners.add(listener);
-               else
-                       allUsersListeners.add(listener);
-               List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null, numberOfPreviousEvents);
-               for (LogEvent evt : lastEvents)
-                       if (everything || evt.getUsername() != null)
-                               dispatchEvent(listener, evt);
-       }
-
-       public synchronized void unregister(ArgeoLogListener listener) {
-               String username = CurrentUser.getUsername();
-               if (username == null)// FIXME
-                       return;
-               if (!userListeners.containsKey(username))
-                       throw new CmsException("No user listeners " + listener + " registered for user " + username);
-               if (!userListeners.get(username).contains(listener))
-                       throw new CmsException("No user listeners " + listener + " registered for user " + username);
-               userListeners.get(username).remove(listener);
-               if (userListeners.get(username).isEmpty())
-                       userListeners.remove(username);
-
-       }
-
-       public synchronized void unregisterForAll(ArgeoLogListener listener) {
-               everythingListeners.remove(listener);
-               allUsersListeners.remove(listener);
-       }
-
-       /** For development purpose, since using regular logging is not easy here */
-       private static void stdOut(Object obj) {
-               System.out.println(obj);
-       }
-
-       private static void stdErr(Object obj) {
-               System.err.println(obj);
-       }
-
-       private static void debug(Object obj) {
-               if (debug)
-                       System.out.println(obj);
-       }
-
-       private static boolean isInternalDebugEnabled() {
-               return debug;
-       }
-
-       // public void setPattern(String pattern) {
-       // this.pattern = pattern;
-       // }
-
-       public void setDisabled(Boolean disabled) {
-               this.disabled = disabled;
-       }
-
-       public void setLevel(String level) {
-               this.level = level;
-       }
-
-       public void setConfiguration(Properties configuration) {
-               this.configuration = configuration;
-       }
-
-       public void updateConfiguration(Properties configuration) {
-               setConfiguration(configuration);
-               reloadConfiguration();
-       }
-
-       public Properties getConfiguration() {
-               return configuration;
-       }
-
-       /**
-        * Reloads configuration (if the configuration {@link Properties} is set)
-        */
-       protected void reloadConfiguration() {
-               if (configuration != null) {
-//                     LogManager.resetConfiguration();
-//                     PropertyConfigurator.configure(configuration);
-               }
-       }
-
-       protected synchronized void processLoggingEvent(LogEvent event) {
-               if (disabled)
-                       return;
-
-               if (dispatching.get())
-                       return;
-
-               if (level != null && !level.trim().equals("")) {
-//                     if (log4jLevel == null || !log4jLevel.toString().equals(level))
-//                             try {
-//                                     log4jLevel = Level.toLevel(level);
-//                             } catch (Exception e) {
-//                                     System.err.println("Log4j level could not be set for level '" + level + "', resetting it to null.");
-//                                     e.printStackTrace();
-//                                     level = null;
-//                             }
-//
-//                     if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
-//                             return;
-//                     }
-               }
-
-               try {
-                       // admin listeners
-                       Iterator<ArgeoLogListener> everythingIt = everythingListeners.iterator();
-                       while (everythingIt.hasNext())
-                               dispatchEvent(everythingIt.next(), event);
-
-                       if (event.getUsername() != null) {
-                               Iterator<ArgeoLogListener> allUsersIt = allUsersListeners.iterator();
-                               while (allUsersIt.hasNext())
-                                       dispatchEvent(allUsersIt.next(), event);
-
-                               if (userListeners.containsKey(event.getUsername())) {
-                                       Iterator<ArgeoLogListener> userIt = userListeners.get(event.getUsername()).iterator();
-                                       while (userIt.hasNext())
-                                               dispatchEvent(userIt.next(), event);
-                               }
-                       }
-               } catch (Exception e) {
-                       stdOut("Cannot process logging event");
-                       e.printStackTrace();
-               }
-       }
-
-       protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
-//             LoggingEvent event = evt.getLoggingEvent();
-//             logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event.getLevel().toString(),
-//                             event.getLoggerName(), event.getThreadName(), event.getMessage(), event.getThrowableStrRep());
-       }
-
-       private class AppenderImpl { //extends AppenderSkeleton {
-               public boolean requiresLayout() {
-                       return false;
-               }
-
-               public void close() {
-               }
-
-//             @Override
-//             protected void append(LoggingEvent event) {
-//                     if (events != null) {
-//                             try {
-//                                     String username = CurrentUser.getUsername();
-//                                     events.put(new LogEvent(username, event));
-//                             } catch (InterruptedException e) {
-//                                     // silent
-//                             }
-//                     }
-//             }
-
-       }
-
-       private class LogDispatcherThread extends Thread {
-               /** encapsulated in order to simplify concurrency management */
-               private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
-
-               public LogDispatcherThread() {
-                       super("Argeo Logging Dispatcher Thread");
-               }
-
-               public void run() {
-                       while (events != null) {
-                               try {
-                                       LogEvent loggingEvent = events.take();
-                                       processLoggingEvent(loggingEvent);
-                                       addLastEvent(loggingEvent);
-                               } catch (InterruptedException e) {
-                                       if (events == null)
-                                               return;
-                               }
-                       }
-               }
-
-               protected synchronized void addLastEvent(LogEvent loggingEvent) {
-                       if (lastEvents.size() >= maxLastEventsCount)
-                               lastEvents.poll();
-                       lastEvents.add(loggingEvent);
-               }
-
-               public synchronized List<LogEvent> getLastEvents(String username, Integer maxCount) {
-                       LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
-                       ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents.size());
-                       int count = 0;
-                       while (it.hasPrevious() && (count < maxCount)) {
-                               LogEvent evt = it.previous();
-                               if (username == null || username.equals(evt.getUsername())) {
-                                       evts.push(evt);
-                                       count++;
-                               }
-                       }
-                       return evts;
-               }
-       }
-
-       private class LogEvent {
-               private final String username;
-//             private final LoggingEvent loggingEvent;
-
-               public LogEvent(String username) {
-                       super();
-                       this.username = username;
-//                     this.loggingEvent = loggingEvent;
-               }
-
-//             @Override
-//             public int hashCode() {
-//                     return loggingEvent.hashCode();
-//             }
-//
-//             @Override
-//             public boolean equals(Object obj) {
-//                     return loggingEvent.equals(obj);
-//             }
-//
-//             @Override
-//             public String toString() {
-//                     return username + "@ " + loggingEvent.toString();
-//             }
-
-               public String getUsername() {
-                       return username;
-               }
-
-//             public LoggingEvent getLoggingEvent() {
-//                     return loggingEvent;
-//             }
-
-       }
-
-       private class Log4jConfWatcherThread extends Thread {
-               private Path log4jConfigurationPath;
-
-               public Log4jConfWatcherThread(Path log4jConfigurationPath) {
-                       super("Log4j Configuration Watcher");
-                       try {
-                               this.log4jConfigurationPath = log4jConfigurationPath.toRealPath();
-                       } catch (IOException e) {
-                               this.log4jConfigurationPath = log4jConfigurationPath.toAbsolutePath();
-                               stdOut("Cannot determine real path for " + log4jConfigurationPath + ": " + e.getMessage());
-                       }
-               }
-
-               public void run() {
-                       Path parentDir = log4jConfigurationPath.getParent();
-                       try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
-                               parentDir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
-                               WatchKey wk;
-                               watching: while ((wk = watchService.take()) != null) {
-                                       for (WatchEvent<?> event : wk.pollEvents()) {
-                                               final Path changed = (Path) event.context();
-                                               if (log4jConfigurationPath.equals(parentDir.resolve(changed))) {
-                                                       if (isInternalDebugEnabled())
-                                                               debug(log4jConfigurationPath + " has changed, reloading.");
-//                                                     PropertyConfigurator.configure(log4jConfigurationPath.toUri().toURL());
-                                               }
-                                       }
-                                       // reset the key
-                                       boolean valid = wk.reset();
-                                       if (!valid) {
-                                               break watching;
-                                       }
-                               }
-                       } catch (IOException | InterruptedException e) {
-                               stdErr("Log4j configuration watcher failed: " + e.getMessage());
-                       }
-               }
-       }
-}
index 871dc8d7f72d2b6ee401e544458b7f1455e6f803..cdcabcb03060902a54a7698d08cc3ec49d51596a 100644 (file)
@@ -285,6 +285,7 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                private StackTraceElement findCallLocation(Level level, Thread thread) {
                        assert level != null;
                        assert thread != null;
+                       // TODO rather use a StackWalker and make it smarter
                        StackTraceElement callLocation = null;
                        if (level.getSeverity() >= callLocationLevel.getSeverity()) {
                                StackTraceElement[] stack = thread.getStackTrace();
@@ -293,12 +294,15 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                                        String className = stack[i].getClassName();
                                        switch (className) {
                                        // TODO make it more configurable
+                                       // FIXME deal with privileges stacks (in Equinox)
                                        case "java.lang.System$Logger":
                                        case "java.util.logging.Logger":
                                        case "org.apache.commons.logging.Log":
                                        case "org.osgi.service.log.Logger":
+                                       case "org.eclipse.osgi.internal.log.LoggerImpl":
                                        case "org.argeo.api.cms.CmsLog":
                                        case "org.slf4j.impl.ArgeoLogger":
+                                       case "org.argeo.cms.internal.osgi.CmsOsgiLogger":
                                        case "org.eclipse.jetty.util.log.Slf4jLog":
                                        case "sun.util.logging.internal.LoggingProviderImpl$JULWrapper":
                                                lowestLoggerInterface = i;