From 0b7c4d15bef603eed5a7b770482e6cf684bbf381 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 21 Feb 2012 18:13:05 +0000 Subject: [PATCH] Logging management git-svn-id: https://svn.argeo.org/commons/trunk@5109 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../main/java/org/argeo/ArgeoLogListener.java | 24 +++ .../org/argeo/util/tabular/TabularColumn.java | 2 +- demo/argeo_node_rcp.properties | 4 +- demo/log4j.properties | 2 +- .../META-INF/spring/monitor.xml | 32 ++++ .../META-INF/spring/osgi.xml | 4 + .../plugins/org.argeo.security.ui/plugin.xml | 6 + .../plugins/org.argeo.security.ui/pom.xml | 5 +- .../security/ui/UserHomePerspective.java | 5 + .../security/ui/views/LogContentProvider.java | 81 ++++++++ .../org/argeo/security/ui/views/LogView.java | 54 ++++++ .../argeo/security/ui/views/UserProfile.java | 1 - .../runtime/org.argeo.security.core/pom.xml | 6 + .../argeo/security/OsAuthenticationToken.java | 4 + .../jcr/OsJcrAuthenticationProvider.java | 15 +- .../argeo/security/log4j/SecureLogger.java | 177 ++++++++++++++++++ .../META-INF/spring/commands.xml | 2 +- .../META-INF/spring/osgi.xml | 1 + .../JackrabbitRepositoryFactory.java | 2 +- .../src/main/java/org/argeo/jcr/JcrUtils.java | 14 ++ .../argeo/jcr/tabular/JcrTabularWriter.java | 2 + 21 files changed, 434 insertions(+), 9 deletions(-) create mode 100644 basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/ArgeoLogListener.java create mode 100644 security/plugins/org.argeo.security.ui/META-INF/spring/monitor.xml create mode 100644 security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java create mode 100644 security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java create mode 100644 security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/log4j/SecureLogger.java diff --git a/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/ArgeoLogListener.java b/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/ArgeoLogListener.java new file mode 100644 index 000000000..8c83db429 --- /dev/null +++ b/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/ArgeoLogListener.java @@ -0,0 +1,24 @@ +package org.argeo; + +/** Framework agnostic interface for log notifications */ +public interface ArgeoLogListener { + /** + * Appends a log + * + * @param username + * authentified user, null for anonymous + * @param level + * INFO, DEBUG, WARN, etc. (logging framework specific) + * @param category + * hierarchy (logging framework specific) + * @param thread + * name of the thread which logged this message + * @param msg + * any object as long as its toString() method returns the + * message + * @param the + * exception in log4j ThrowableStrRep format + */ + public void appendLog(String username, Long timestamp, String level, + String category, String thread, Object msg, String[] exception); +} diff --git a/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/util/tabular/TabularColumn.java b/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/util/tabular/TabularColumn.java index ab3b74ba4..fda5f0b73 100644 --- a/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/util/tabular/TabularColumn.java +++ b/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/util/tabular/TabularColumn.java @@ -6,7 +6,7 @@ public class TabularColumn { /** * JCR types, see * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html - * ?javax/jcr/Property.html + * ?javax/jcr/PropertyType.html */ private Integer type; diff --git a/demo/argeo_node_rcp.properties b/demo/argeo_node_rcp.properties index cd705db2d..d9eaf77d2 100644 --- a/demo/argeo_node_rcp.properties +++ b/demo/argeo_node_rcp.properties @@ -5,8 +5,8 @@ org.argeo.node.repo.jackrabbit,\ org.argeo.security.dao.os,\ org.argeo.security.equinox,\ -org.argeo.security.ui.initialPerspective=org.argeo.osgi.ui.explorer.perspective - +#org.argeo.security.ui.initialPerspective=org.argeo.osgi.ui.explorer.perspective +org.argeo.security.ui.initialPerspective==org.argeo.security.ui.userHomePerspective #argeo.node.repo.uri=http://localhost:7070/org.argeo.jcr.webapp/remoting/node log4j.configuration=file:../../log4j.properties diff --git a/demo/log4j.properties b/demo/log4j.properties index 5be6d57f1..15ce795ea 100644 --- a/demo/log4j.properties +++ b/demo/log4j.properties @@ -12,7 +12,7 @@ log4j.logger.org.apache.coyote=INFO log4j.logger.org.apache.directory.server=ERROR log4j.logger.org.apache.jackrabbit.core.query.lucene=ERROR -log4j.logger.org.springframework.security.context=DEBUG +#log4j.logger.org.springframework.security.context=DEBUG ## Appenders # console is set to be a ConsoleAppender. diff --git a/security/plugins/org.argeo.security.ui/META-INF/spring/monitor.xml b/security/plugins/org.argeo.security.ui/META-INF/spring/monitor.xml new file mode 100644 index 000000000..f2faeb2fd --- /dev/null +++ b/security/plugins/org.argeo.security.ui/META-INF/spring/monitor.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/security/plugins/org.argeo.security.ui/META-INF/spring/osgi.xml b/security/plugins/org.argeo.security.ui/META-INF/spring/osgi.xml index 9e357a36d..010fd3bba 100644 --- a/security/plugins/org.argeo.security.ui/META-INF/spring/osgi.xml +++ b/security/plugins/org.argeo.security.ui/META-INF/spring/osgi.xml @@ -8,7 +8,11 @@ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" osgi:default-timeout="30000"> + + + \ No newline at end of file diff --git a/security/plugins/org.argeo.security.ui/plugin.xml b/security/plugins/org.argeo.security.ui/plugin.xml index 6f6886359..d016464e8 100644 --- a/security/plugins/org.argeo.security.ui/plugin.xml +++ b/security/plugins/org.argeo.security.ui/plugin.xml @@ -28,6 +28,12 @@ name="Profile" restorable="true"> + + diff --git a/security/plugins/org.argeo.security.ui/pom.xml b/security/plugins/org.argeo.security.ui/pom.xml index dd85204cc..f51404d80 100644 --- a/security/plugins/org.argeo.security.ui/pom.xml +++ b/security/plugins/org.argeo.security.ui/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.argeo.commons.security @@ -33,6 +34,7 @@ org.eclipse.ui;resolution:=optional,org.eclipse.rap.ui;resolution:=optional,org.eclipse.core.runtime org.argeo.eclipse.spring, + org.apache.log4j;resolution:=optional, * @@ -85,5 +87,6 @@ org.slf4j com.springsource.slf4j.org.apache.commons.logging + diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java index 329c1ade1..1ce7364e8 100644 --- a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java @@ -1,5 +1,6 @@ package org.argeo.security.ui; +import org.argeo.security.ui.views.LogView; import org.argeo.security.ui.views.UserProfile; import org.eclipse.ui.IFolderLayout; import org.eclipse.ui.IPageLayout; @@ -18,6 +19,10 @@ public class UserHomePerspective implements IPerspectiveFactory { 0.30f, editorArea); left.addView(UserProfile.ID); // left.addView(RolesView.ID); + + IFolderLayout bottom = layout.createFolder("bottom", + IPageLayout.BOTTOM, 0.30f, editorArea); + bottom.addView(LogView.ID); } } diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java new file mode 100644 index 000000000..5e28228a1 --- /dev/null +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java @@ -0,0 +1,81 @@ +package org.argeo.security.ui.views; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.argeo.ArgeoLogListener; +import org.eclipse.jface.viewers.ILazyContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; + +/** A content provider maintaing an array of lines */ +class LogContentProvider implements ILazyContentProvider, ArgeoLogListener { + private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); + + private final TableViewer viewer; + private List lines; + + public LogContentProvider(TableViewer viewer) { + this.viewer = viewer; + } + + public synchronized void dispose() { + lines = null; + } + + @SuppressWarnings("unchecked") + public synchronized void inputChanged(Viewer viewer, Object oldInput, + Object newInput) { + lines = (List) newInput; + if (lines == null) + return; + this.viewer.setItemCount(lines.size()); + } + + public void updateElement(int index) { + viewer.replace(lines.get(index), index); + } + + public synchronized void appendLog(String username, Long timestamp, + String level, String category, String thread, Object msg, + String[] exception) { + // check if valid + if (lines == null) + return; + + String message = msg.toString(); + StringBuffer buf = new StringBuffer(""); + buf.append(dateFormat.format(new Date(timestamp))).append(" "); + buf.append(level).append(" "); + int count = 0; + String lastLine = null; + for (String line : message.split("\n")) { + if (count == 0) + lastLine = buf + line; + else + lastLine = line; + lines.add(lastLine); + count++; + } + + if (exception != null) { + for (String ste : exception) { + lastLine = ste; + lines.add(lastLine); + } + } + final Object lastElement = lastLine; + viewer.getTable().getDisplay().asyncExec(new Runnable() { + public void run() { + viewer.setItemCount(lines.size()); + if (lastElement != null) + viewer.reveal(lastElement); + } + }); + } + // private class LogLine { + // private String message; + // } +} \ No newline at end of file diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java new file mode 100644 index 000000000..e49400757 --- /dev/null +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java @@ -0,0 +1,54 @@ +package org.argeo.security.ui.views; + +import java.util.ArrayList; + +import org.argeo.ArgeoLogListener; +import org.argeo.security.ui.SecurityUiPlugin; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.ViewPart; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +/** + * Display log lines with a virtual table. Register and unregisters a + * {@link ArgeoLogListener} via OSGi services. + */ +public class LogView extends ViewPart { + public static String ID = SecurityUiPlugin.PLUGIN_ID + ".logView"; + + private TableViewer viewer; + + private LogContentProvider logContentProvider; + + private ServiceRegistration serviceRegistration; + + @Override + public void createPartControl(Composite parent) { + viewer = new TableViewer(parent, SWT.VIRTUAL); + viewer.setLabelProvider(new LabelProvider()); + logContentProvider = new LogContentProvider(viewer); + serviceRegistration = getBundleContext().registerService( + ArgeoLogListener.class.getName(), logContentProvider, null); + viewer.setContentProvider(logContentProvider); + viewer.setUseHashlookup(true); + viewer.setInput(new ArrayList()); + } + + @Override + public void setFocus() { + viewer.getTable().setFocus(); + } + + @Override + public void dispose() { + if (serviceRegistration != null) + serviceRegistration.unregister(); + } + + private BundleContext getBundleContext() { + return SecurityUiPlugin.getDefault().getBundle().getBundleContext(); + } +} diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java index f28ab5733..4d17b42c6 100644 --- a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java @@ -14,7 +14,6 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; import org.eclipse.ui.part.ViewPart; import org.springframework.security.Authentication; diff --git a/security/runtime/org.argeo.security.core/pom.xml b/security/runtime/org.argeo.security.core/pom.xml index c4a2c98e0..a91656c9b 100644 --- a/security/runtime/org.argeo.security.core/pom.xml +++ b/security/runtime/org.argeo.security.core/pom.xml @@ -87,6 +87,12 @@ com.springsource.slf4j.org.apache.commons.logging + + org.apache.log4j + com.springsource.org.apache.log4j + true + + org.junit diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java index 61ec539c6..8ba3f9fbc 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java @@ -71,7 +71,11 @@ public class OsAuthenticationToken implements Authentication { this(null); } + /** @return the name, or null if not yet logged */ public String getName() { + Subject subject = Subject.getSubject(AccessController.getContext()); + if (subject == null) + return null; return getUser().getName(); } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java index bccd1c616..5307673ce 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java @@ -4,6 +4,7 @@ import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.security.Privilege; import org.argeo.ArgeoException; import org.argeo.jcr.JcrUtils; @@ -17,10 +18,12 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider { private Repository repository; private String securityWorkspace = "security"; private Session securitySession; + private Session nodeSession; public void init() { try { securitySession = repository.login(securityWorkspace); + nodeSession = repository.login(); } catch (RepositoryException e) { throw new ArgeoException("Cannot initialize", e); } @@ -28,6 +31,7 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider { public void destroy() { JcrUtils.logoutQuietly(securitySession); + JcrUtils.logoutQuietly(nodeSession); } public Authentication authenticate(Authentication authentication) @@ -40,8 +44,17 @@ public class OsJcrAuthenticationProvider extends OsAuthenticationProvider { String username = System.getProperty("user.name"); Node userProfile = JcrUtils.createUserProfileIfNeeded( securitySession, username); - JcrUserDetails.checkAccountStatus(userProfile); + + // each user should have a writable area in the default workspace of + // the node + Node userNodeHome = JcrUtils.createUserHomeIfNeeded(nodeSession, + username); + JcrUtils.addPrivilege(nodeSession, userNodeHome.getPath(), + username, Privilege.JCR_ALL); + if (nodeSession.hasPendingChanges()) + nodeSession.save(); + // user details JcrUserDetails userDetails = new JcrUserDetails(userProfile, authen .getCredentials().toString(), getBaseAuthorities()); diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/log4j/SecureLogger.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/log4j/SecureLogger.java new file mode 100644 index 000000000..70945f07c --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/log4j/SecureLogger.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * 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 org.argeo.security.log4j; + +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.spi.LoggingEvent; +import org.argeo.ArgeoException; +import org.argeo.ArgeoLogListener; +import org.springframework.security.Authentication; +import org.springframework.security.context.SecurityContext; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken; + +/** Not meant to be used directly in standard log4j config */ +public class SecureLogger { + private List listeners; + + private Boolean disabled = false; + + private String level = null; + + private Level log4jLevel = null; + // private Layout layout; + + private Properties configuration; + + private AppenderImpl appender; + + /** Marker to prevent stack overflow */ + private ThreadLocal dispatching = new ThreadLocal() { + + @Override + protected Boolean initialValue() { + return false; + } + }; + + public void init() { + try { + // if (layout != null) + // setLayout(layout); + // else + // setLayout(new PatternLayout(pattern)); + appender = new AppenderImpl(); + + if (configuration != null) + PropertyConfigurator.configure(configuration); + + Logger.getRootLogger().addAppender(appender); + } catch (Exception e) { + throw new ArgeoException("Cannot initialize log4j"); + } + } + + public void destroy() throws Exception { + Logger.getRootLogger().removeAppender(appender); + } + + // public void setLayout(Layout layout) { + // this.layout = layout; + // } + + /** For development purpose, since using regular logging is not easy here */ + static void stdOut(Object obj) { + System.out.println(obj); + } + + // 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 setListeners(List listeners) { + this.listeners = listeners; + } + + public void setConfiguration(Properties configuration) { + this.configuration = configuration; + } + + private class AppenderImpl extends AppenderSkeleton { + public boolean requiresLayout() { + return false; + } + + public void close() { + } + + @Override + protected void append(LoggingEvent 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.getLevel().isGreaterOrEqual(log4jLevel)) { + return; + } + } + + try { + Thread currentThread = Thread.currentThread(); + String username = null; + + // find username + SecurityContext securityContext = SecurityContextHolder + .getContext(); + if (securityContext != null) { + Authentication authentication = securityContext + .getAuthentication(); + if (authentication != null) { + if (authentication instanceof AnonymousAuthenticationToken) { + username = null; + } else { + username = authentication.getName(); + } + } + } + + // Spring OSGi safe + Iterator it = listeners.iterator(); + while (it.hasNext()) { + ArgeoLogListener logListener = it.next(); + logListener.appendLog(username, event.getTimeStamp(), event + .getLevel().toString(), event.getLoggerName(), + currentThread.getName(), event.getMessage(), event.getThrowableStrRep()); + } + } catch (Exception e) { + stdOut("Cannot process logging event"); + e.printStackTrace(); + } + } + + } +} diff --git a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml index 96ad94dbd..2bdd659e5 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml +++ b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/commands.xml @@ -21,7 +21,7 @@ - + diff --git a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/osgi.xml b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/osgi.xml index 4708847a2..7c415e0cc 100644 --- a/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/osgi.xml +++ b/server/plugins/org.argeo.jcr.ui.explorer/META-INF/spring/osgi.xml @@ -16,6 +16,7 @@ + diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java index 65bdf2939..d98448c7c 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java @@ -39,7 +39,7 @@ public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory else if (parameters.containsKey(JcrUtils.REPOSITORY_URI)) uri = parameters.get(JcrUtils.REPOSITORY_URI).toString(); - if (uri == null) + if (uri != null) repository = createRemoteRepository(uri); if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) { diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 3aa649378..7d8b6565e 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -64,6 +64,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; +import org.argeo.util.security.SimplePrincipal; /** Utility methods to simplify common JCR operations. */ public class JcrUtils implements ArgeoJcrConstants { @@ -1367,6 +1368,19 @@ public class JcrUtils implements ArgeoJcrConstants { /* * SECURITY */ + + /** + * Convenience method for adding a single privilege to a principal (user or + * role), typically jcr:all + */ + public static void addPrivilege(Session session, String path, + String principal, String privilege) throws RepositoryException { + List privileges = new ArrayList(); + privileges.add(session.getAccessControlManager().privilegeFromName( + privilege)); + addPrivileges(session, path, new SimplePrincipal(principal), privileges); + } + /** * Add privileges on a path to a {@link Principal}. The path must already * exist. diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/tabular/JcrTabularWriter.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/tabular/JcrTabularWriter.java index 0727b784e..55a0a312f 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/tabular/JcrTabularWriter.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/tabular/JcrTabularWriter.java @@ -24,11 +24,13 @@ public class JcrTabularWriter implements TabularWriter { private Node contentNode; private ByteArrayOutputStream out; private CsvWriter csvWriter; + private final List columns; /** Creates a table node */ public JcrTabularWriter(Node tableNode, List columns, String contentNodeType) { try { + this.columns = columns; for (TabularColumn column : columns) { String normalized = JcrUtils.replaceInvalidChars(column .getName()); -- 2.30.2