Author: markt
Date: Wed Feb 10 21:26:46 2016
New Revision: 1729742

URL: http://svn.apache.org/viewvc?rev=1729742&view=rev
Log:
Next stage of JASPIC implementation (excluding the changes to AuthenticatorBase 
to integrate JASPIC support).
With the necessary integration, this code passes the javaee7-samples JASPIC 
unit tests as far as the lifecycle tests (which currently all fail).

Added:
    
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
   (with props)
    
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
   (with props)
    
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties
   (with props)
    
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java 
  (with props)
Modified:
    
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
    
tomcat/trunk/test/org/apache/catalina/authenticator/jaspic/TestPersistentProviderRegistrations.java
    tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java

Added: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java?rev=1729742&view=auto
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
 (added)
+++ 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
 Wed Feb 10 21:26:46 2016
@@ -0,0 +1,298 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.catalina.authenticator.jaspic;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.security.auth.message.config.AuthConfigFactory;
+import javax.security.auth.message.config.AuthConfigProvider;
+import javax.security.auth.message.config.RegistrationListener;
+
+import org.apache.catalina.Globals;
+import 
org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations.Provider;
+import 
org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations.Providers;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
+
+public class AuthConfigFactoryImpl extends AuthConfigFactory {
+
+    private static final Log log = 
LogFactory.getLog(AuthConfigFactoryImpl.class);
+    private static final StringManager sm = 
StringManager.getManager(AuthConfigFactoryImpl.class);
+
+    private static final String CONFIG_PATH = "conf/jaspic-providers.xml";
+    private static final File CONFIG_FILE =
+            new File(System.getProperty(Globals.CATALINA_BASE_PROP), 
CONFIG_PATH);
+    private static final Object CONFIG_FILE_LOCK = new Object();
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    private final Map<String,RegistrationContextImpl> registrations = new 
ConcurrentHashMap<>();
+
+
+    // TODO: Handle parallel deployment. Can this be done if web application is
+    //       not aware it is being deployed in parallel?
+    public AuthConfigFactoryImpl() {
+        loadPersistentRegistrations();
+    }
+
+
+    @Override
+    public AuthConfigProvider getConfigProvider(String layer, String 
appContext,
+            RegistrationListener listener) {
+        String registrationID = getRegistrarionID(layer, appContext);
+        RegistrationContextImpl registrationContext = 
registrations.get(registrationID);
+        if (registrationContext != null) {
+            registrationContext.addListener(null);
+            return registrationContext.getProvider();
+        }
+        return null;
+    }
+
+
+    @Override
+    public String registerConfigProvider(String className,
+            @SuppressWarnings("rawtypes") Map properties, String layer, String 
appContext,
+            String description) {
+        String registrationID =
+                doRegisterConfigProvider(className, properties, layer, 
appContext, description);
+        savePersistentRegistrations();
+        return registrationID;
+    }
+
+
+    @SuppressWarnings("unchecked")
+    private String doRegisterConfigProvider(String className,
+            @SuppressWarnings("rawtypes") Map properties, String layer, String 
appContext,
+            String description) {
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("authConfigFactoryImpl.registerClass",
+                    className, layer, appContext));
+        }
+        Class<?> clazz;
+        AuthConfigProvider provider = null;
+        try {
+            clazz = Class.forName(className, true, 
Thread.currentThread().getContextClassLoader());
+        } catch (ClassNotFoundException e) {
+            // Ignore so the re-try below can proceed
+        }
+        try {
+            clazz = Class.forName(className);
+            Constructor<?> constructor = clazz.getConstructor(Map.class, 
AuthConfigFactory.class);
+            provider = (AuthConfigProvider) 
constructor.newInstance(properties, this);
+        } catch (ClassNotFoundException | NoSuchMethodException | 
InstantiationException |
+                IllegalAccessException | IllegalArgumentException | 
InvocationTargetException e) {
+            throw new SecurityException(e);
+        }
+
+        String registrationID = getRegistrarionID(layer, appContext);
+        registrations.put(registrationID,
+                new RegistrationContextImpl(layer, appContext, description, 
true, provider, properties));
+        return registrationID;
+    }
+
+
+    @Override
+    public String registerConfigProvider(AuthConfigProvider provider, String 
layer,
+            String appContext, String description) {
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("authConfigFactoryImpl.registerInstance",
+                    provider.getClass().getName(), layer, appContext));
+        }
+        String registrationID = getRegistrarionID(layer, appContext);
+        registrations.put(registrationID,
+                new RegistrationContextImpl(layer, appContext, description, 
false, provider, null));
+        return registrationID;
+    }
+
+
+    @Override
+    public boolean removeRegistration(String registrationID) {
+        return registrations.remove(registrationID) != null;
+    }
+
+
+    @Override
+    public String[] detachListener(RegistrationListener listener, String 
layer, String appContext) {
+        String registrationID = getRegistrarionID(layer, appContext);
+        RegistrationContextImpl registrationContext = 
registrations.get(registrationID);
+        if (registrationContext.removeListener(listener)) {
+            return new String[] { registrationID };
+        }
+        return EMPTY_STRING_ARRAY;
+    }
+
+
+    @Override
+    public String[] getRegistrationIDs(AuthConfigProvider provider) {
+        if (provider == null) {
+            return registrations.keySet().toArray(EMPTY_STRING_ARRAY);
+        } else {
+            List<String> results = new ArrayList<>();
+            for (Entry<String,RegistrationContextImpl> entry : 
registrations.entrySet()) {
+                if (provider.equals(entry.getValue().getProvider())) {
+                    results.add(entry.getKey());
+                }
+            }
+            return results.toArray(EMPTY_STRING_ARRAY);
+        }
+    }
+
+
+    @Override
+    public RegistrationContext getRegistrationContext(String registrationID) {
+        return registrations.get(registrationID);
+    }
+
+
+    @Override
+    public void refresh() {
+        loadPersistentRegistrations();
+    }
+
+
+    private String getRegistrarionID(String layer, String appContext) {
+        return layer + ":" + appContext;
+    }
+
+
+    private void loadPersistentRegistrations() {
+        synchronized (CONFIG_FILE_LOCK) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("authConfigFactoryImpl.load",
+                        CONFIG_FILE.getAbsolutePath()));
+            }
+            if (!CONFIG_FILE.isFile()) {
+                return;
+            }
+            Providers providers = 
PersistentProviderRegistrations.loadProviders(CONFIG_FILE);
+            for (Provider provider : providers.getProviders()) {
+                doRegisterConfigProvider(provider.getClassName(), 
provider.getProperties(),
+                        provider.getLayer(), provider.getAppContext(), 
provider.getDescription());
+            }
+        }
+    }
+
+
+    private void savePersistentRegistrations() {
+        synchronized (CONFIG_FILE_LOCK) {
+            Providers providers = new Providers();
+            for (Entry<String,RegistrationContextImpl> entry : 
registrations.entrySet()) {
+                if (entry.getValue().isPersistent()) {
+                    Provider provider = new Provider();
+                    provider.setAppContext(entry.getValue().getAppContext());
+                    
provider.setClassName(entry.getValue().getProvider().getClass().getName());
+                    provider.setDescription(entry.getValue().getDescription());
+                    provider.setLayer(entry.getValue().getMessageLayer());
+                    for (Entry<String,String> property : 
entry.getValue().getProperties().entrySet()) {
+                        provider.addProperty(property.getKey(), 
property.getValue());
+                    }
+                    providers.addProvider(provider);
+                }
+            }
+            PersistentProviderRegistrations.writeProviders(providers, 
CONFIG_FILE);
+        }
+    }
+
+
+    private static class RegistrationContextImpl implements 
RegistrationContext {
+
+        private RegistrationContextImpl(String messageLayer, String 
appContext, String description,
+                boolean persistent, AuthConfigProvider provider, 
Map<String,String> properties) {
+            this.messageLayer = messageLayer;
+            this.appContext = appContext;
+            this.description = description;
+            this.persistent = persistent;
+            this.provider = provider;
+            Map<String,String> propertiesCopy = new HashMap<>();
+            if (properties != null) {
+                propertiesCopy.putAll(properties);
+            }
+            this.properties = Collections.unmodifiableMap(propertiesCopy);
+        }
+
+        private final String messageLayer;
+        private final String appContext;
+        private final String description;
+        private final boolean persistent;
+        private final AuthConfigProvider provider;
+        private final Map<String,String> properties;
+        private final List<RegistrationListener> listeners = new 
CopyOnWriteArrayList<>();
+
+        @Override
+        public String getMessageLayer() {
+            return messageLayer;
+        }
+
+
+        @Override
+        public String getAppContext() {
+            return appContext;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+
+        @Override
+        public boolean isPersistent() {
+            return persistent;
+        }
+
+
+        private AuthConfigProvider getProvider() {
+            return provider;
+        }
+
+
+        private void addListener(RegistrationListener listener) {
+            if (listener != null) {
+                listeners.add(listener);
+            }
+        }
+
+
+        private Map<String,String> getProperties() {
+            return properties;
+        }
+
+
+        private boolean removeListener(RegistrationListener listener) {
+            boolean result = false;
+            Iterator<RegistrationListener> iter = listeners.iterator();
+            while (iter.hasNext()) {
+                if (iter.next().equals(listener)) {
+                    iter.remove();
+                }
+            }
+            return result;
+        }
+    }
+}

Propchange: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java?rev=1729742&view=auto
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
 (added)
+++ 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
 Wed Feb 10 21:26:46 2016
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.catalina.authenticator.jaspic;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.message.callback.CallerPrincipalCallback;
+import javax.security.auth.message.callback.GroupPrincipalCallback;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
+
+public class CallbackHandlerImpl implements CallbackHandler {
+
+    private static final Log log = 
LogFactory.getLog(CallbackHandlerImpl.class);
+    private static final StringManager sm = 
StringManager.getManager(CallbackHandlerImpl.class);
+
+    private Request request;
+    private String name;
+    private Principal principal;
+    private Subject subject;
+    private String[] groups;
+
+
+    public CallbackHandlerImpl(Request request) {
+        this.request = request;
+    }
+
+
+    @Override
+    public void handle(Callback[] callbacks) throws IOException, 
UnsupportedCallbackException {
+        if (callbacks != null) {
+            // Need to combine data from multiple callbacks so use this to hold
+            // the data
+            // Process the callbacks
+            for (Callback callback : callbacks) {
+                if (callback instanceof CallerPrincipalCallback) {
+                    CallerPrincipalCallback cpc = (CallerPrincipalCallback) 
callback;
+                    name = cpc.getName();
+                    principal = cpc.getPrincipal();
+                    subject = cpc.getSubject();
+                } else if (callback instanceof GroupPrincipalCallback) {
+                    GroupPrincipalCallback gpc = (GroupPrincipalCallback) 
callback;
+                    groups = gpc.getGroups();
+                } else {
+                    
log.error(sm.getString("callbackHandlerImpl.jaspicCallbackMissing",
+                            callback.getClass().getName()));
+                }
+            }
+
+            // Create the GenericPrincipal
+            GenericPrincipal gp = getGenericPrincipal();
+            if (gp != null) {
+                request.setUserPrincipal(gp);
+
+                if (subject != null) {
+                    subject.getPrivateCredentials().add(gp);
+                }
+            }
+        }
+    }
+
+
+    public GenericPrincipal getGenericPrincipal() {
+        String name = this.name;
+        if (name == null && principal != null) {
+            name = principal.getName();
+        }
+        if (name == null) {
+            return null;
+        }
+        List<String> roles;
+        if (groups == null || groups.length == 0) {
+            roles = Collections.emptyList();
+        } else {
+            roles = Arrays.asList(groups);
+        }
+
+        return new GenericPrincipal(name, null, roles, principal);
+    }
+}

Propchange: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties?rev=1729742&view=auto
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties
 (added)
+++ 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties
 Wed Feb 10 21:26:46 2016
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+authConfigFactoryImpl.load=Loading persistent provider registrations from [{0}]
+authConfigFactoryImpl.registerClass=Registering class [{0}] for layer [{1}] 
and application context [{2}]
+authConfigFactoryImpl.registerInstance=Registering instance of type[{0}] for 
layer [{1}] and application context [{2}]
+
+callbackHandlerImpl.jaspicCallbackMissing=Unsupported JASPIC callback of type 
[{0}] received which was ignored
+
+jaspicAuthenticator.authenticate=Authenticating request for [{0}] via JASPIC
+
+persistentProviderRegistrations.deleteFail=The temporary file [{0}] cannot be 
deleted
+persistentProviderRegistrations.existsDeleteFail=The temporary file [{0}] 
already exists and cannot be deleted
+persistentProviderRegistrations.moveFail=Failed to move [{0}] to [{1}]
\ No newline at end of file

Propchange: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/LocalStrings.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java?rev=1729742&view=auto
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java 
(added)
+++ 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java 
Wed Feb 10 21:26:46 2016
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.catalina.authenticator.jaspic;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.message.MessageInfo;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.connector.Request;
+import org.apache.tomcat.util.res.StringManager;
+
+public class MessageInfoImpl implements MessageInfo {
+    protected static final StringManager sm = 
StringManager.getManager(MessageInfoImpl.class);
+
+    public static final String IS_MANDATORY = 
"javax.security.auth.message.MessagePolicy.isMandatory";
+
+    private final Map<String, Object> map = new HashMap<>();
+    private Request request;
+    private HttpServletResponse response;
+
+    public MessageInfoImpl() {
+    }
+
+    public MessageInfoImpl(Request request, HttpServletResponse response, 
boolean authMandatory) {
+        this.request = request;
+        this.response = response;
+        map.put(IS_MANDATORY, Boolean.toString(authMandatory));
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    // JASPIC uses raw types
+    public Map getMap() {
+        return map;
+    }
+
+    @Override
+    public Object getRequestMessage() {
+        return request;
+    }
+
+    @Override
+    public Object getResponseMessage() {
+        return response;
+    }
+
+    @Override
+    public void setRequestMessage(Object request) {
+        if (!(request instanceof Request)) {
+            throw new 
IllegalArgumentException(sm.getString("authenticator.jaspic.badRequestType",
+                    request.getClass().getName()));
+        }
+        this.request = (Request) request;
+    }
+
+    @Override
+    public void setResponseMessage(Object response) {
+        if (!(response instanceof HttpServletResponse)) {
+            throw new 
IllegalArgumentException(sm.getString("authenticator.jaspic.badResponseType",
+                    response.getClass().getName()));
+        }
+        this.response = (HttpServletResponse) response;
+    }
+}
\ No newline at end of file

Propchange: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java?rev=1729742&r1=1729741&r2=1729742&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
 (original)
+++ 
tomcat/trunk/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
 Wed Feb 10 21:26:46 2016
@@ -18,32 +18,50 @@ package org.apache.catalina.authenticato
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.res.StringManager;
 import org.xml.sax.SAXException;
 
+/**
+ * Utility class for the loading and saving of JASPIC persistent provider
+ * registrations.
+ */
 final class PersistentProviderRegistrations {
 
+    private static final Log log = 
LogFactory.getLog(PersistentProviderRegistrations.class);
+    private static final StringManager sm =
+            StringManager.getManager(PersistentProviderRegistrations.class);
+
+
     private PersistentProviderRegistrations() {
         // Utility class. Hide default constructor
     }
 
 
-    static Providers getProviders(File configFile) {
+    static Providers loadProviders(File configFile) {
         try (InputStream is = new FileInputStream(configFile)) {
             // Construct a digester to read the XML input file
             Digester digester = new Digester();
 
             try {
                 
digester.setFeature("http://apache.org/xml/features/allow-java-encodings";, 
true);
-                // TODO: Configure the digester to validate the input against
-                //       the XSD
+                digester.setValidating(true);
+                digester.setNamespaceAware(true);
             } catch (Exception e) {
                 throw new SecurityException(e);
             }
@@ -72,6 +90,85 @@ final class PersistentProviderRegistrati
     }
 
 
+    static void writeProviders(Providers providers, File configFile) {
+        File configFileOld = new File(configFile.getAbsolutePath() + ".old");
+        File configFileNew = new File(configFile.getAbsolutePath() + ".new");
+
+        // Remove left over temporary files if present
+        if (configFileOld.exists()) {
+            if (configFileOld.delete()) {
+                throw new SecurityException(sm.getString(
+                        "persistentProviderRegistrations.existsDeleteFail",
+                        configFileOld.getAbsolutePath()));
+            }
+        }
+        if (configFileNew.exists()) {
+            if (configFileNew.delete()) {
+                throw new SecurityException(sm.getString(
+                        "persistentProviderRegistrations.existsDeleteFail",
+                        configFileNew.getAbsolutePath()));
+            }
+        }
+
+        // Write out the providers to the temporary new file
+        try (OutputStream fos = new FileOutputStream(configFileNew);
+                Writer writer = new OutputStreamWriter(fos, 
StandardCharsets.UTF_8)) {
+            writer.write(
+                    "<?xml version='1.0' encoding='utf-8'?>\n" +
+                    "<jaspic-providers\n" +
+                    "    xmlns=\"http://tomcat.apache.org/xml\"\n"; +
+                    "    
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"; +
+                    "    xsi:schemaLocation=\"http://tomcat.apache.org/xml 
jaspic-providers.xsd\"\n" +
+                    "    version=\"1.0\">\n");
+            for (Provider provider : providers.providers) {
+                writer.write("  <provider className=\"");
+                writer.write(provider.getClassName());
+                writer.write("\" layer=\"");
+                writer.write(provider.getLayer());
+                writer.write("\" appContext=\"");
+                writer.write(provider.getAppContext());
+                if (provider.getDescription() != null) {
+                    writer.write("\" description=\"");
+                    writer.write(provider.getDescription());
+                }
+                writer.write("\">\n");
+                for (Entry<String,String> entry : 
provider.getProperties().entrySet()) {
+                    writer.write("    <property name=\"");
+                    writer.write(entry.getKey());
+                    writer.write("\" value=\"");
+                    writer.write(entry.getValue());
+                    writer.write("\"/>\n");
+                }
+                writer.write("  </provider>\n");
+            }
+            writer.write("</jaspic-providers>\n");
+        } catch (IOException e) {
+            configFileNew.delete();
+            throw new SecurityException(e);
+        }
+
+        // Move the current file out of the way
+        if (configFile.isFile()) {
+            if (!configFile.renameTo(configFileOld)) {
+                throw new 
SecurityException(sm.getString("persistentProviderRegistrations.moveFail",
+                        configFile.getAbsolutePath(), 
configFileOld.getAbsolutePath()));
+            }
+        }
+
+        // Move the new file into place
+        if (!configFileNew.renameTo(configFile)) {
+            throw new 
SecurityException(sm.getString("persistentProviderRegistrations.moveFail",
+                    configFileNew.getAbsolutePath(), 
configFile.getAbsolutePath()));
+        }
+
+        // Remove the old file
+        if (configFileOld.exists() && !configFileOld.delete()) {
+            log.warn(sm.getString("persistentProviderRegistrations.deleteFail",
+                    configFileOld.getAbsolutePath()));
+        }
+    }
+
+
     public static class Providers {
         private final List<Provider> providers = new ArrayList<>();
 
@@ -128,6 +225,9 @@ final class PersistentProviderRegistrati
         public void addProperty(Property property) {
             properties.put(property.getName(), property.getValue());
         }
+        void addProperty(String name, String value) {
+            properties.put(name, value);
+        }
         public Map<String,String> getProperties() {
             return properties;
         }

Modified: 
tomcat/trunk/test/org/apache/catalina/authenticator/jaspic/TestPersistentProviderRegistrations.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/authenticator/jaspic/TestPersistentProviderRegistrations.java?rev=1729742&r1=1729741&r2=1729742&view=diff
==============================================================================
--- 
tomcat/trunk/test/org/apache/catalina/authenticator/jaspic/TestPersistentProviderRegistrations.java
 (original)
+++ 
tomcat/trunk/test/org/apache/catalina/authenticator/jaspic/TestPersistentProviderRegistrations.java
 Wed Feb 10 21:26:46 2016
@@ -29,7 +29,7 @@ public class TestPersistentProviderRegis
     @Test
     public void testLoadEmpty() {
         File f = new File("test/conf/jaspic-test-01.xml");
-        Providers result = PersistentProviderRegistrations.getProviders(f);
+        Providers result = PersistentProviderRegistrations.loadProviders(f);
         Assert.assertEquals(0,  result.getProviders().size());
     }
 
@@ -37,9 +37,14 @@ public class TestPersistentProviderRegis
     @Test
     public void testLoadSimple() {
         File f = new File("test/conf/jaspic-test-02.xml");
-        Providers result = PersistentProviderRegistrations.getProviders(f);
-        Assert.assertEquals(1,  result.getProviders().size());
-        Provider p = result.getProviders().get(0);
+        Providers result = PersistentProviderRegistrations.loadProviders(f);
+        validateSimple(result);
+    }
+
+
+    private void validateSimple(Providers providers) {
+        Assert.assertEquals(1,  providers.getProviders().size());
+        Provider p = providers.getProviders().get(0);
         Assert.assertEquals("a", p.getClassName());
         Assert.assertEquals("b", p.getLayer());
         Assert.assertEquals("c", p.getAppContext());
@@ -49,4 +54,34 @@ public class TestPersistentProviderRegis
         Assert.assertEquals("f", p.getProperties().get("e"));
         Assert.assertEquals("h", p.getProperties().get("g"));
     }
+
+
+    @Test
+    public void testSaveSimple() {
+        File f = new File("test/conf/jaspic-test-03.xml");
+        if (f.exists()) {
+            Assert.assertTrue(f.delete());
+        }
+
+        // Create a config and write it out
+        Providers start = new Providers();
+        Provider p = new Provider();
+        p.setClassName("a");
+        p.setLayer("b");
+        p.setAppContext("c");
+        p.setDescription("d");
+        p.addProperty("e", "f");
+        p.addProperty("g", "h");
+        start.addProvider(p);
+        PersistentProviderRegistrations.writeProviders(start, f);
+
+        // Read it back
+        Providers end = PersistentProviderRegistrations.loadProviders(f);
+
+        validateSimple(end);
+
+        if (f.exists()) {
+            f.delete();
+        }
+    }
 }

Modified: tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java?rev=1729742&r1=1729741&r2=1729742&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java 
(original)
+++ tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java Wed 
Feb 10 21:26:46 2016
@@ -34,6 +34,7 @@ import org.junit.Test;
 
 import org.apache.catalina.Context;
 import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
 import org.apache.tomcat.util.buf.ByteChunk;
 
 public class TestContextConfig extends TomcatBaseTest {
@@ -201,4 +202,24 @@ public class TestContextConfig extends T
             Assert.assertTrue(result, result.indexOf(expectedBody) > -1);
         }
     }
+
+
+    @Test
+    public void testUser01() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        StandardHost host = (StandardHost) tomcat.getHost();
+        host.setUnpackWARs(true);
+        host.setAutoDeploy(true);
+        tomcat.start();
+
+
+        StandardContext ctx = new StandardContext();
+        ctx.setDocBase("D://test1");
+        ctx.setPath("/test1");
+        ctx.addLifecycleListener(new ContextConfig());
+
+        host.addChild(ctx);
+
+        System.out.println("done");
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to