Modified: 
turbine/core/trunk/src/java/org/apache/turbine/services/schedule/WorkerThread.java
URL: 
http://svn.apache.org/viewvc/turbine/core/trunk/src/java/org/apache/turbine/services/schedule/WorkerThread.java?rev=1812628&r1=1812627&r2=1812628&view=diff
==============================================================================
--- 
turbine/core/trunk/src/java/org/apache/turbine/services/schedule/WorkerThread.java
 (original)
+++ 
turbine/core/trunk/src/java/org/apache/turbine/services/schedule/WorkerThread.java
 Thu Oct 19 12:34:25 2017
@@ -1,101 +1,101 @@
-package org.apache.turbine.services.schedule;
-
-/*
- * 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.
- */
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.turbine.modules.ScheduledJobLoader;
-
-/**
- * Wrapper for a <code>JobEntry</code> to actually perform the job's action.
- *
- * @author <a href="mailto:[email protected]";>Dave Bryson</a>
- * @author <a href="mailto:[email protected]";>Daniel Rall</a>
- * @author <a href="mailto:[email protected]";>Henning P. Schmiedehausen</a>
- * @author <a href="mailto:[email protected]";>Quinton McCombs</a>
- * @version $Id: WorkerThread.java 534527 2007-05-02 16:10:59Z tv $
- */
-public class WorkerThread
-        implements Runnable
-{
-    /**
-     * The <code>JobEntry</code> to run.
-     */
-    private JobEntry je = null;
-
-    /** Logging */
-    private static Log log = LogFactory.getLog(ScheduleService.LOGGER_NAME);
-
-    /**
-     * Creates a new worker to run the specified <code>JobEntry</code>.
-     *
-     * @param je The <code>JobEntry</code> to create a worker for.
-     */
-    public WorkerThread(JobEntry je)
-    {
-        this.je = je;
-    }
-
-    /**
-     * Run the job.
-     */
-    @Override
-    public void run()
-    {
-        if (je == null || je.isActive())
-        {
-            return;
-        }
-
-        try
-        {
-            if (!je.isActive())
-            {
-                je.setActive(true);
-                logStateChange("started");
-                ScheduledJobLoader.getInstance().exec(je, je.getTask());
-            }
-        }
-        catch (Exception e)
-        {
-            log.error("Error in WorkerThread for scheduled job #" +
-                    je.getJobId() + ", task: " + je.getTask(), e);
-        }
-        finally
-        {
-            if (je.isActive())
-            {
-                je.setActive(false);
-                logStateChange("completed");
-            }
-        }
-    }
-
-    /**
-     * Macro to log <code>JobEntry</code> status information.
-     *
-     * @param state The new state of the <code>JobEntry</code>.
-     */
-    private final void logStateChange(String state)
-    {
-        log.debug("Scheduled job #" + je.getJobId() + ' ' + state +
-                ", task: " + je.getTask());
-    }
-}
+package org.apache.turbine.services.schedule;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.turbine.modules.ScheduledJobLoader;
+
+/**
+ * Wrapper for a <code>JobEntry</code> to actually perform the job's action.
+ *
+ * @author <a href="mailto:[email protected]";>Dave Bryson</a>
+ * @author <a href="mailto:[email protected]";>Daniel Rall</a>
+ * @author <a href="mailto:[email protected]";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:[email protected]";>Quinton McCombs</a>
+ * @version $Id: WorkerThread.java 534527 2007-05-02 16:10:59Z tv $
+ */
+public class WorkerThread
+        implements Runnable
+{
+    /**
+     * The <code>JobEntry</code> to run.
+     */
+    private JobEntry je = null;
+
+    /** Logging */
+    private static Log log = LogFactory.getLog(ScheduleService.LOGGER_NAME);
+
+    /**
+     * Creates a new worker to run the specified <code>JobEntry</code>.
+     *
+     * @param je The <code>JobEntry</code> to create a worker for.
+     */
+    public WorkerThread(JobEntry je)
+    {
+        this.je = je;
+    }
+
+    /**
+     * Run the job.
+     */
+    @Override
+    public void run()
+    {
+        if (je == null || je.isActive())
+        {
+            return;
+        }
+
+        try
+        {
+            if (!je.isActive())
+            {
+                je.setActive(true);
+                logStateChange("started");
+                ScheduledJobLoader.getInstance().exec(je, je.getTask());
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("Error in WorkerThread for scheduled job #" +
+                    je.getJobId() + ", task: " + je.getTask(), e);
+        }
+        finally
+        {
+            if (je.isActive())
+            {
+                je.setActive(false);
+                logStateChange("completed");
+            }
+        }
+    }
+
+    /**
+     * Macro to log <code>JobEntry</code> status information.
+     *
+     * @param state The new state of the <code>JobEntry</code>.
+     */
+    private final void logStateChange(String state)
+    {
+        log.debug("Scheduled job #" + je.getJobId() + ' ' + state +
+                ", task: " + je.getTask());
+    }
+}

Modified: 
turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultSecurityService.java
URL: 
http://svn.apache.org/viewvc/turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultSecurityService.java?rev=1812628&r1=1812627&r2=1812628&view=diff
==============================================================================
--- 
turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultSecurityService.java
 (original)
+++ 
turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultSecurityService.java
 Thu Oct 19 12:34:25 2017
@@ -125,7 +125,7 @@ public class DefaultSecurityService
         {
             this.userManager =
                     (UserManager) 
Class.forName(userManagerClassName).newInstance();
-            
+
             userManager.init(conf);
         }
         catch (Exception e)

Modified: 
turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultUserManager.java
URL: 
http://svn.apache.org/viewvc/turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultUserManager.java?rev=1812628&r1=1812627&r2=1812628&view=diff
==============================================================================
--- 
turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultUserManager.java
 (original)
+++ 
turbine/core/trunk/src/java/org/apache/turbine/services/security/DefaultUserManager.java
 Thu Oct 19 12:34:25 2017
@@ -1,516 +1,516 @@
-package org.apache.turbine.services.security;
-
-
-/*
- * 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.
- */
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.fulcrum.factory.FactoryService;
-import org.apache.fulcrum.security.acl.AccessControlList;
-import org.apache.fulcrum.security.model.turbine.TurbineUserManager;
-import org.apache.fulcrum.security.model.turbine.entity.TurbineUser;
-import org.apache.fulcrum.security.util.DataBackendException;
-import org.apache.fulcrum.security.util.EntityExistsException;
-import org.apache.fulcrum.security.util.PasswordMismatchException;
-import org.apache.fulcrum.security.util.UnknownEntityException;
-import org.apache.fulcrum.security.util.UserSet;
-import org.apache.turbine.om.security.TurbineUserDelegate;
-import org.apache.turbine.om.security.User;
-import org.apache.turbine.services.InitializationException;
-import org.apache.turbine.services.ServiceManager;
-import org.apache.turbine.services.TurbineServices;
-import org.apache.turbine.util.ObjectUtils;
-
-/**
- * Default user manager.
- *
- * The user manager wraps Fulcrum security user objects into
- * Turbine-specific ones.
- * 
- * 
- * <ol><li>either in a method with the same name (and very similar signature) 
- * <li>or mapped to method names as listed below:
- * 
- * <ul>
- * <li>method(s) in this manager -> Fulcrum manager method(s)
- * <li>{@link #createAccount(User, String)}createAccount -> addUser(User, 
String)
- * <li> {@link #removeAccount(User)} -> removeUser(User)
- * <li>{@link #store(User)} -> saveUser(User)
- * <li>{@link #retrieve(String)} and {@link #retrieve(String, String)} -> 
getUser(String), getUser(String, String)
- * <li>{@link #retrieveList(Object)} ->getAllUsers()
- * <li>{@link #accountExists(String)}, {@link #accountExists(User)} -> 
checkExists(String), checkExists(User)
- *  
- * In this way all public methods of Fulcrum {@link TurbineUserManager} 
interface are used by reference of the Fulcrum delegate {@link #umDelegate} 
- * and wrapped by this manager.
- *
- * @author <a href="mailto:[email protected]";>Thomas Vandahl</a>
- * @version $Id: PassiveUserManager.java 1096130 2011-04-23 10:37:19Z ludwig $
- */
-public class DefaultUserManager implements UserManager
-{
-    /** Fulcrum user manager instance to delegate to */
-    private TurbineUserManager umDelegate = null;
-
-    private FactoryService factoryService = null;
-
-    /** The user class, which the UserManager uses as wrapper for Fulcrum 
{@link TurbineUser} */
-    private String userWrapperClass;
-
-
-    /** Logging */
-    private static Log log = LogFactory.getLog(DefaultUserManager.class);
-
-    /**
-     * Wrap a Fulcrum user object into a Turbine user object
-     *
-     * @param user the user object to delegate to
-     *
-     * @return the wrapped object
-     */
-    protected <U extends User> U wrap(TurbineUser user)
-    {
-       // U u = (U)new DefaultUserImpl(user);
-        @SuppressWarnings("unchecked")
-        U u = (U) getUserWrapper(user);
-        return u;
-    }
-
-    /**
-     * Exception could be ignored, as it is tested before in {@link 
#init(Configuration)}.
-     *
-     * @param user the user object to wrap
-     * @return instance extending {@link User}
-     */
-    @SuppressWarnings("unchecked")
-       public <U extends User> U getUserWrapper(TurbineUser user)
-    {
-               try
-               {
-            Object params[] = new Object[] { user };
-            String signature[] = new String[] { TurbineUser.class.getName() };
-            return (U) factoryService.getInstance(getUserWrapperClass(), 
params, signature);
-               }
-               catch (Exception e)
-               {
-                       log.error("after init/late instantiation exception", e);
-                       return null; // (U)new DefaultUserImpl(user);
-               }
-       }
-
-    /**
-     * Get the wrapper class for user objects
-     *
-     * @return the wrapper class name
-     */
-    public String getUserWrapperClass()
-    {
-               return userWrapperClass;
-       }
-
-    /**
-     * Set the wrapper class for user objects
-     *
-     * @param userWrapperClass2 the wrapper class name
-     */
-    public void setUserWrapperClass(String userWrapperClass2)
-    {
-               userWrapperClass = userWrapperClass2;
-       }
-
-       /**
-     * Initializes the UserManager
-     *
-     * @param conf A Configuration object to init this Manager
-     */
-    @Override
-    public void init(Configuration conf) throws InitializationException
-    {
-        ServiceManager manager = TurbineServices.getInstance();
-        this.umDelegate = 
(TurbineUserManager)manager.getService(TurbineUserManager.ROLE);
-
-        String userWrapperClass = conf.getString(
-                SecurityService.USER_WRAPPER_KEY,
-                SecurityService.USER_WRAPPER_DEFAULT);
-
-//        String userClass = conf.getString(
-//                SecurityService.USER_KEY,
-//                SecurityService.USER_DEFAULT);
-
-        try
-        {
-               factoryService = 
(FactoryService)manager.getService(FactoryService.ROLE);
-
-            //  check instantiation
-
-               // should provide default constructor
-               TurbineUser turbineUser = umDelegate.getUserInstance();
-                               //(TurbineUser) 
factoryService.getInstance(userClass);
-            Object params[] = new Object[] { turbineUser };
-            String signature[] = new String[] { TurbineUser.class.getName() };
-
-            // Just check if exceptions would occur
-            factoryService.getInstance(userWrapperClass, params, signature);
-
-            this.setUserWrapperClass(userWrapperClass);
-        }
-        catch (Exception e)
-           {
-              throw new InitializationException("Failed to instantiate user 
wrapper class", e);
-           }
-
-    }
-
-
-       /**
-     * Check whether a specified user's account exists.
-     *
-     * The login name is used for looking up the account.
-     *
-     * @param user The user to be checked.
-     * @return true if the specified account exists
-     * @throws DataBackendException if there was an error accessing the data 
backend.
-     */
-    @Override
-    public boolean accountExists(User user)
-            throws DataBackendException
-    {
-        return umDelegate.checkExists(user);
-    }
-
-    /**
-     * Check whether a specified user's account exists.
-     *
-     * The login name is used for looking up the account.
-     *
-     * @param userName The name of the user to be checked.
-     * @return true if the specified account exists
-     * @throws DataBackendException if there was an error accessing the data 
backend.
-     */
-    @Override
-    public boolean accountExists(String userName)
-            throws DataBackendException
-    {
-        return umDelegate.checkExists(userName);
-    }
-
-    /**
-     * Retrieve a user from persistent storage using username as the
-     * key.
-     *
-     * @param username the name of the user.
-     * @return an User object.
-     * @throws UnknownEntityException if the user's record does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public <U extends User> U retrieve(String username)
-            throws UnknownEntityException, DataBackendException
-    {
-        TurbineUser u = umDelegate.getUser(username);
-        return wrap(u);
-    }
-
-    /**
-     * Retrieve a set of users that meet the specified criteria.
-     *
-     * As the keys for the criteria, you should use the constants that
-     * are defined in {@link User} interface, plus the names
-     * of the custom attributes you added to your user representation
-     * in the data storage. Use verbatim names of the attributes -
-     * without table name prefix in case of DB implementation.
-     *
-     * @param criteria The criteria of selection.
-     * @return a List of users meeting the criteria.
-     * @throws DataBackendException if there is a problem accessing the
-     *         storage.
-     */
-    @Override
-    public List<? extends User> retrieveList(Object criteria)
-            throws DataBackendException
-    {
-        UserSet uset = umDelegate.getAllUsers();
-        List<User> userList = new ArrayList<User>();
-
-        for (org.apache.fulcrum.security.entity.User u : uset)
-        {
-            TurbineUser tu = (TurbineUser)u;
-            userList.add(wrap(tu));
-        }
-
-        return userList;
-    }
-
-    /**
-     * Retrieve a user from persistent storage using username as the
-     * key, and authenticate the user. The implementation may chose
-     * to authenticate to the server as the user whose data is being
-     * retrieved.
-     *
-     * @param username the name of the user.
-     * @param password the user supplied password.
-     * @return an User object.
-     * @throws PasswordMismatchException if the supplied password was
-     *            incorrect.
-     * @throws UnknownEntityException if the user's record does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public <U extends User> U retrieve(String username, String password)
-            throws PasswordMismatchException, UnknownEntityException,
-            DataBackendException
-    {
-        TurbineUser u = umDelegate.getUser(username, password);
-        return wrap(u);
-    }
-
-    /**
-     * Save an User object to persistent storage. User's record is
-     * required to exist in the storage.
-     *
-     * @param user an User object to store.
-     * @throws UnknownEntityException if the user's record does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public void store(User user)
-            throws UnknownEntityException, DataBackendException
-    {
-        try
-        {
-            
user.setObjectdata(ObjectUtils.serializeMap(user.getPermStorage()));
-        }
-        catch (Exception e)
-        {
-            throw new DataBackendException("Could not serialize permanent 
storage", e);
-        }
-
-        umDelegate.saveUser(((TurbineUserDelegate)user).getUserDelegate());
-    }
-
-    /**
-     * Saves User data when the session is unbound. The user account is 
required
-     * to exist in the storage.
-     *
-     * LastLogin, AccessCounter, persistent pull tools, and any data stored
-     * in the permData hashtable that is not mapped to a column will be saved.
-     *
-     * @throws UnknownEntityException if the user's account does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public void saveOnSessionUnbind(User user)
-            throws UnknownEntityException, DataBackendException
-    {
-        store(user);
-    }
-
-    /**
-     * Authenticate an User with the specified password. If authentication
-     * is successful the method returns nothing. If there are any problems,
-     * exception was thrown.
-     *
-     * @param user an User object to authenticate.
-     * @param password the user supplied password.
-     * @throws PasswordMismatchException if the supplied password was
-     *            incorrect.
-     * @throws UnknownEntityException if the user's record does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public void authenticate(User user, String password)
-            throws PasswordMismatchException, UnknownEntityException,
-            DataBackendException
-    {
-        umDelegate.authenticate(user, password);
-    }
-
-    /**
-     * Creates new user account with specified attributes.
-     *
-     * @param user the object describing account to be created.
-     * @param initialPassword The password to use for the object creation
-     *
-     * @throws DataBackendException if there was an error accessing the data 
backend.
-     * @throws EntityExistsException if the user account already exists.
-     */
-    @Override
-    public void createAccount(User user, String initialPassword)
-            throws EntityExistsException, DataBackendException
-    {
-        umDelegate.addUser(user, initialPassword);
-    }
-
-    /**
-     * Removes an user account from the system.
-     *
-     * @param user the object describing the account to be removed.
-     * @throws DataBackendException if there was an error accessing the data 
backend.
-     * @throws UnknownEntityException if the user account is not present.
-     */
-    @Override
-    public void removeAccount(User user)
-            throws UnknownEntityException, DataBackendException
-    {
-        umDelegate.removeUser(user);
-    }
-
-    /**
-     * Change the password for an User.
-     *
-     * @param user an User to change password for.
-     * @param oldPassword the current password supplied by the user.
-     * @param newPassword the current password requested by the user.
-     * @throws PasswordMismatchException if the supplied password was
-     *            incorrect.
-     * @throws UnknownEntityException if the user's record does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public void changePassword(User user, String oldPassword,
-                               String newPassword)
-            throws PasswordMismatchException, UnknownEntityException,
-            DataBackendException
-    {
-        umDelegate.changePassword(
-                ((TurbineUserDelegate)user).getUserDelegate(),
-                oldPassword, newPassword);
-    }
-
-    /**
-     * Forcibly sets new password for an User.
-     *
-     * This is supposed by the administrator to change the forgotten or
-     * compromised passwords. Certain implementations of this feature
-     * would require administrative level access to the authenticating
-     * server / program.
-     *
-     * @param user an User to change password for.
-     * @param password the new password.
-     * @throws UnknownEntityException if the user's record does not
-     *            exist in the database.
-     * @throws DataBackendException if there is a problem accessing the
-     *            storage.
-     */
-    @Override
-    public void forcePassword(User user, String password)
-            throws UnknownEntityException, DataBackendException
-    {
-        umDelegate.forcePassword(user, password);
-    }
-
-    /**
-     * Constructs an User object to represent an anonymous user of the
-     * application.
-     *
-     * @return An anonymous Turbine User.
-     * @throws UnknownEntityException
-     *             if the anonymous User object couldn't be constructed.
-     */
-    @Override
-    public <T extends User> T getAnonymousUser() throws UnknownEntityException
-    {
-        TurbineUser u = umDelegate.getAnonymousUser();
-        return wrap(u);
-    }
-
-    /**
-     * Checks whether a passed user object matches the anonymous user pattern
-     * according to the configured user manager
-     *
-     * @param u a user object
-     *
-     * @return True if this is an anonymous user
-     *
-     */
-    @Override
-    public boolean isAnonymousUser(User u)
-    {
-        return umDelegate.isAnonymousUser(u);
-    }
-
-    /**
-     * Construct a blank User object.
-     *
-     * This method calls getUserClass, and then creates a new object using the
-     * default constructor.
-     *
-     * @return an object implementing User interface.
-     * @throws DataBackendException
-     *             if the object could not be instantiated.
-     */
-    @Override
-    public <T extends User> T getUserInstance() throws DataBackendException
-    {
-        TurbineUser u = umDelegate.getUserInstance();
-        return wrap(u);
-    }
-
-    /**
-     * Construct a blank User object.
-     *
-     * This method calls getUserClass, and then creates a new object using the
-     * default constructor.
-     *
-     * @param userName
-     *            The name of the user.
-     *
-     * @return an object implementing User interface.
-     * @throws DataBackendException
-     *             if the object could not be instantiated.
-     */
-    @Override
-    public <T extends User> T getUserInstance(String userName) throws 
DataBackendException
-    {
-        TurbineUser u = umDelegate.getUserInstance(userName);
-        return wrap(u);
-    }
-
-    /**
-     * Return a Class object representing the system's chosen implementation of
-     * of ACL interface.
-     *
-     * @return systems's chosen implementation of ACL interface.
-     * @throws UnknownEntityException
-     *             if the implementation of ACL interface could not be
-     *             determined, or does not exist.
-     */
-    @Override
-    public <T extends AccessControlList> T getACL(User user) throws 
UnknownEntityException
-    {
-        return umDelegate.getACL(user);
-    }
-}
+package org.apache.turbine.services.security;
+
+
+/*
+ * 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.
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fulcrum.factory.FactoryService;
+import org.apache.fulcrum.security.acl.AccessControlList;
+import org.apache.fulcrum.security.model.turbine.TurbineUserManager;
+import org.apache.fulcrum.security.model.turbine.entity.TurbineUser;
+import org.apache.fulcrum.security.util.DataBackendException;
+import org.apache.fulcrum.security.util.EntityExistsException;
+import org.apache.fulcrum.security.util.PasswordMismatchException;
+import org.apache.fulcrum.security.util.UnknownEntityException;
+import org.apache.fulcrum.security.util.UserSet;
+import org.apache.turbine.om.security.TurbineUserDelegate;
+import org.apache.turbine.om.security.User;
+import org.apache.turbine.services.InitializationException;
+import org.apache.turbine.services.ServiceManager;
+import org.apache.turbine.services.TurbineServices;
+import org.apache.turbine.util.ObjectUtils;
+
+/**
+ * Default user manager.
+ *
+ * The user manager wraps Fulcrum security user objects into
+ * Turbine-specific ones.
+ *
+ *
+ * <ol><li>either in a method with the same name (and very similar signature)
+ * <li>or mapped to method names as listed below:
+ *
+ * <ul>
+ * <li>method(s) in this manager -> Fulcrum manager method(s)
+ * <li>{@link #createAccount(User, String)}createAccount -> addUser(User, 
String)
+ * <li> {@link #removeAccount(User)} -> removeUser(User)
+ * <li>{@link #store(User)} -> saveUser(User)
+ * <li>{@link #retrieve(String)} and {@link #retrieve(String, String)} -> 
getUser(String), getUser(String, String)
+ * <li>{@link #retrieveList(Object)} ->getAllUsers()
+ * <li>{@link #accountExists(String)}, {@link #accountExists(User)} -> 
checkExists(String), checkExists(User)
+ *
+ * In this way all public methods of Fulcrum {@link TurbineUserManager} 
interface are used by reference of the Fulcrum delegate {@link #umDelegate}
+ * and wrapped by this manager.
+ *
+ * @author <a href="mailto:[email protected]";>Thomas Vandahl</a>
+ * @version $Id: PassiveUserManager.java 1096130 2011-04-23 10:37:19Z ludwig $
+ */
+public class DefaultUserManager implements UserManager
+{
+    /** Fulcrum user manager instance to delegate to */
+    private TurbineUserManager umDelegate = null;
+
+    private FactoryService factoryService = null;
+
+    /** The user class, which the UserManager uses as wrapper for Fulcrum 
{@link TurbineUser} */
+    private String userWrapperClass;
+
+
+    /** Logging */
+    private static Log log = LogFactory.getLog(DefaultUserManager.class);
+
+    /**
+     * Wrap a Fulcrum user object into a Turbine user object
+     *
+     * @param user the user object to delegate to
+     *
+     * @return the wrapped object
+     */
+    protected <U extends User> U wrap(TurbineUser user)
+    {
+       // U u = (U)new DefaultUserImpl(user);
+        @SuppressWarnings("unchecked")
+        U u = (U) getUserWrapper(user);
+        return u;
+    }
+
+    /**
+     * Exception could be ignored, as it is tested before in {@link 
#init(Configuration)}.
+     *
+     * @param user the user object to wrap
+     * @return instance extending {@link User}
+     */
+    @SuppressWarnings("unchecked")
+       public <U extends User> U getUserWrapper(TurbineUser user)
+    {
+               try
+               {
+            Object params[] = new Object[] { user };
+            String signature[] = new String[] { TurbineUser.class.getName() };
+            return (U) factoryService.getInstance(getUserWrapperClass(), 
params, signature);
+               }
+               catch (Exception e)
+               {
+                       log.error("after init/late instantiation exception", e);
+                       return null; // (U)new DefaultUserImpl(user);
+               }
+       }
+
+    /**
+     * Get the wrapper class for user objects
+     *
+     * @return the wrapper class name
+     */
+    public String getUserWrapperClass()
+    {
+               return userWrapperClass;
+       }
+
+    /**
+     * Set the wrapper class for user objects
+     *
+     * @param userWrapperClass2 the wrapper class name
+     */
+    public void setUserWrapperClass(String userWrapperClass2)
+    {
+               userWrapperClass = userWrapperClass2;
+       }
+
+       /**
+     * Initializes the UserManager
+     *
+     * @param conf A Configuration object to init this Manager
+     */
+    @Override
+    public void init(Configuration conf) throws InitializationException
+    {
+        ServiceManager manager = TurbineServices.getInstance();
+        this.umDelegate = 
(TurbineUserManager)manager.getService(TurbineUserManager.ROLE);
+
+        String userWrapperClass = conf.getString(
+                SecurityService.USER_WRAPPER_KEY,
+                SecurityService.USER_WRAPPER_DEFAULT);
+
+//        String userClass = conf.getString(
+//                SecurityService.USER_KEY,
+//                SecurityService.USER_DEFAULT);
+
+        try
+        {
+               factoryService = 
(FactoryService)manager.getService(FactoryService.ROLE);
+
+            //  check instantiation
+
+               // should provide default constructor
+               TurbineUser turbineUser = umDelegate.getUserInstance();
+                               //(TurbineUser) 
factoryService.getInstance(userClass);
+            Object params[] = new Object[] { turbineUser };
+            String signature[] = new String[] { TurbineUser.class.getName() };
+
+            // Just check if exceptions would occur
+            factoryService.getInstance(userWrapperClass, params, signature);
+
+            this.setUserWrapperClass(userWrapperClass);
+        }
+        catch (Exception e)
+           {
+              throw new InitializationException("Failed to instantiate user 
wrapper class", e);
+           }
+
+    }
+
+
+       /**
+     * Check whether a specified user's account exists.
+     *
+     * The login name is used for looking up the account.
+     *
+     * @param user The user to be checked.
+     * @return true if the specified account exists
+     * @throws DataBackendException if there was an error accessing the data 
backend.
+     */
+    @Override
+    public boolean accountExists(User user)
+            throws DataBackendException
+    {
+        return umDelegate.checkExists(user);
+    }
+
+    /**
+     * Check whether a specified user's account exists.
+     *
+     * The login name is used for looking up the account.
+     *
+     * @param userName The name of the user to be checked.
+     * @return true if the specified account exists
+     * @throws DataBackendException if there was an error accessing the data 
backend.
+     */
+    @Override
+    public boolean accountExists(String userName)
+            throws DataBackendException
+    {
+        return umDelegate.checkExists(userName);
+    }
+
+    /**
+     * Retrieve a user from persistent storage using username as the
+     * key.
+     *
+     * @param username the name of the user.
+     * @return an User object.
+     * @throws UnknownEntityException if the user's record does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public <U extends User> U retrieve(String username)
+            throws UnknownEntityException, DataBackendException
+    {
+        TurbineUser u = umDelegate.getUser(username);
+        return wrap(u);
+    }
+
+    /**
+     * Retrieve a set of users that meet the specified criteria.
+     *
+     * As the keys for the criteria, you should use the constants that
+     * are defined in {@link User} interface, plus the names
+     * of the custom attributes you added to your user representation
+     * in the data storage. Use verbatim names of the attributes -
+     * without table name prefix in case of DB implementation.
+     *
+     * @param criteria The criteria of selection.
+     * @return a List of users meeting the criteria.
+     * @throws DataBackendException if there is a problem accessing the
+     *         storage.
+     */
+    @Override
+    public List<? extends User> retrieveList(Object criteria)
+            throws DataBackendException
+    {
+        UserSet uset = umDelegate.getAllUsers();
+        List<User> userList = new ArrayList<User>();
+
+        for (org.apache.fulcrum.security.entity.User u : uset)
+        {
+            TurbineUser tu = (TurbineUser)u;
+            userList.add(wrap(tu));
+        }
+
+        return userList;
+    }
+
+    /**
+     * Retrieve a user from persistent storage using username as the
+     * key, and authenticate the user. The implementation may chose
+     * to authenticate to the server as the user whose data is being
+     * retrieved.
+     *
+     * @param username the name of the user.
+     * @param password the user supplied password.
+     * @return an User object.
+     * @throws PasswordMismatchException if the supplied password was
+     *            incorrect.
+     * @throws UnknownEntityException if the user's record does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public <U extends User> U retrieve(String username, String password)
+            throws PasswordMismatchException, UnknownEntityException,
+            DataBackendException
+    {
+        TurbineUser u = umDelegate.getUser(username, password);
+        return wrap(u);
+    }
+
+    /**
+     * Save an User object to persistent storage. User's record is
+     * required to exist in the storage.
+     *
+     * @param user an User object to store.
+     * @throws UnknownEntityException if the user's record does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public void store(User user)
+            throws UnknownEntityException, DataBackendException
+    {
+        try
+        {
+            
user.setObjectdata(ObjectUtils.serializeMap(user.getPermStorage()));
+        }
+        catch (Exception e)
+        {
+            throw new DataBackendException("Could not serialize permanent 
storage", e);
+        }
+
+        umDelegate.saveUser(((TurbineUserDelegate)user).getUserDelegate());
+    }
+
+    /**
+     * Saves User data when the session is unbound. The user account is 
required
+     * to exist in the storage.
+     *
+     * LastLogin, AccessCounter, persistent pull tools, and any data stored
+     * in the permData hashtable that is not mapped to a column will be saved.
+     *
+     * @throws UnknownEntityException if the user's account does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public void saveOnSessionUnbind(User user)
+            throws UnknownEntityException, DataBackendException
+    {
+        store(user);
+    }
+
+    /**
+     * Authenticate an User with the specified password. If authentication
+     * is successful the method returns nothing. If there are any problems,
+     * exception was thrown.
+     *
+     * @param user an User object to authenticate.
+     * @param password the user supplied password.
+     * @throws PasswordMismatchException if the supplied password was
+     *            incorrect.
+     * @throws UnknownEntityException if the user's record does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public void authenticate(User user, String password)
+            throws PasswordMismatchException, UnknownEntityException,
+            DataBackendException
+    {
+        umDelegate.authenticate(user, password);
+    }
+
+    /**
+     * Creates new user account with specified attributes.
+     *
+     * @param user the object describing account to be created.
+     * @param initialPassword The password to use for the object creation
+     *
+     * @throws DataBackendException if there was an error accessing the data 
backend.
+     * @throws EntityExistsException if the user account already exists.
+     */
+    @Override
+    public void createAccount(User user, String initialPassword)
+            throws EntityExistsException, DataBackendException
+    {
+        umDelegate.addUser(user, initialPassword);
+    }
+
+    /**
+     * Removes an user account from the system.
+     *
+     * @param user the object describing the account to be removed.
+     * @throws DataBackendException if there was an error accessing the data 
backend.
+     * @throws UnknownEntityException if the user account is not present.
+     */
+    @Override
+    public void removeAccount(User user)
+            throws UnknownEntityException, DataBackendException
+    {
+        umDelegate.removeUser(user);
+    }
+
+    /**
+     * Change the password for an User.
+     *
+     * @param user an User to change password for.
+     * @param oldPassword the current password supplied by the user.
+     * @param newPassword the current password requested by the user.
+     * @throws PasswordMismatchException if the supplied password was
+     *            incorrect.
+     * @throws UnknownEntityException if the user's record does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public void changePassword(User user, String oldPassword,
+                               String newPassword)
+            throws PasswordMismatchException, UnknownEntityException,
+            DataBackendException
+    {
+        umDelegate.changePassword(
+                ((TurbineUserDelegate)user).getUserDelegate(),
+                oldPassword, newPassword);
+    }
+
+    /**
+     * Forcibly sets new password for an User.
+     *
+     * This is supposed by the administrator to change the forgotten or
+     * compromised passwords. Certain implementations of this feature
+     * would require administrative level access to the authenticating
+     * server / program.
+     *
+     * @param user an User to change password for.
+     * @param password the new password.
+     * @throws UnknownEntityException if the user's record does not
+     *            exist in the database.
+     * @throws DataBackendException if there is a problem accessing the
+     *            storage.
+     */
+    @Override
+    public void forcePassword(User user, String password)
+            throws UnknownEntityException, DataBackendException
+    {
+        umDelegate.forcePassword(user, password);
+    }
+
+    /**
+     * Constructs an User object to represent an anonymous user of the
+     * application.
+     *
+     * @return An anonymous Turbine User.
+     * @throws UnknownEntityException
+     *             if the anonymous User object couldn't be constructed.
+     */
+    @Override
+    public <T extends User> T getAnonymousUser() throws UnknownEntityException
+    {
+        TurbineUser u = umDelegate.getAnonymousUser();
+        return wrap(u);
+    }
+
+    /**
+     * Checks whether a passed user object matches the anonymous user pattern
+     * according to the configured user manager
+     *
+     * @param u a user object
+     *
+     * @return True if this is an anonymous user
+     *
+     */
+    @Override
+    public boolean isAnonymousUser(User u)
+    {
+        return umDelegate.isAnonymousUser(u);
+    }
+
+    /**
+     * Construct a blank User object.
+     *
+     * This method calls getUserClass, and then creates a new object using the
+     * default constructor.
+     *
+     * @return an object implementing User interface.
+     * @throws DataBackendException
+     *             if the object could not be instantiated.
+     */
+    @Override
+    public <T extends User> T getUserInstance() throws DataBackendException
+    {
+        TurbineUser u = umDelegate.getUserInstance();
+        return wrap(u);
+    }
+
+    /**
+     * Construct a blank User object.
+     *
+     * This method calls getUserClass, and then creates a new object using the
+     * default constructor.
+     *
+     * @param userName
+     *            The name of the user.
+     *
+     * @return an object implementing User interface.
+     * @throws DataBackendException
+     *             if the object could not be instantiated.
+     */
+    @Override
+    public <T extends User> T getUserInstance(String userName) throws 
DataBackendException
+    {
+        TurbineUser u = umDelegate.getUserInstance(userName);
+        return wrap(u);
+    }
+
+    /**
+     * Return a Class object representing the system's chosen implementation of
+     * of ACL interface.
+     *
+     * @return systems's chosen implementation of ACL interface.
+     * @throws UnknownEntityException
+     *             if the implementation of ACL interface could not be
+     *             determined, or does not exist.
+     */
+    @Override
+    public <T extends AccessControlList> T getACL(User user) throws 
UnknownEntityException
+    {
+        return umDelegate.getACL(user);
+    }
+}

Modified: 
turbine/core/trunk/src/java/org/apache/turbine/services/security/SecurityService.java
URL: 
http://svn.apache.org/viewvc/turbine/core/trunk/src/java/org/apache/turbine/services/security/SecurityService.java?rev=1812628&r1=1812627&r2=1812628&view=diff
==============================================================================
--- 
turbine/core/trunk/src/java/org/apache/turbine/services/security/SecurityService.java
 (original)
+++ 
turbine/core/trunk/src/java/org/apache/turbine/services/security/SecurityService.java
 Thu Oct 19 12:34:25 2017
@@ -73,13 +73,13 @@ public interface SecurityService
      */
     String USER_MANAGER_DEFAULT
             = PassiveUserManager.class.getName();
-    
+
     /**
      * the key within services's properties for user implementation
      * classname (wrapper.class)
      */
     String USER_WRAPPER_KEY = "wrapper.class";
-    
+
     /**
      * the default implementation of {@link User} interface
      * (org.apache.turbine.om.security.DefaultUserImpl)

Modified: 
turbine/core/trunk/src/java/org/apache/turbine/services/ui/TurbineUIService.java
URL: 
http://svn.apache.org/viewvc/turbine/core/trunk/src/java/org/apache/turbine/services/ui/TurbineUIService.java?rev=1812628&r1=1812627&r2=1812628&view=diff
==============================================================================
--- 
turbine/core/trunk/src/java/org/apache/turbine/services/ui/TurbineUIService.java
 (original)
+++ 
turbine/core/trunk/src/java/org/apache/turbine/services/ui/TurbineUIService.java
 Thu Oct 19 12:34:25 2017
@@ -1,543 +1,543 @@
-package org.apache.turbine.services.ui;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.filefilter.DirectoryFileFilter;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.turbine.Turbine;
-import org.apache.turbine.services.InitializationException;
-import org.apache.turbine.services.TurbineBaseService;
-import org.apache.turbine.services.TurbineServices;
-import org.apache.turbine.services.pull.PullService;
-import org.apache.turbine.services.pull.tools.UITool;
-import org.apache.turbine.services.servlet.ServletService;
-import org.apache.turbine.util.ServerData;
-import org.apache.turbine.util.uri.DataURI;
-
-/**
- * The UI service provides for shared access to User Interface (skin) files,
- * as well as the ability for non-default skin files to inherit properties from
- * a default skin.  Use TurbineUI to access skin properties from your screen
- * classes and action code. UITool is provided as a pull tool for accessing
- * skin properties from your templates.
- *
- * @author <a href="mailto:[email protected]";>Jason van Zyl</a>
- * @author <a href="mailto:[email protected]";>James Coltman</a>
- * @author <a href="mailto:[email protected]";>Henning P. Schmiedehausen</a>
- * @author <a href="mailto:[email protected]";>Scott Eade</a>
- * @author <a href="[email protected]">Thomas Vandahl</a>
- * @version $Id$
- * @see UIService
- * @see UITool
- */
-public class TurbineUIService
-        extends TurbineBaseService
-        implements UIService
-{
-    /** Logging. */
-    private static Log log = LogFactory.getLog(TurbineUIService.class);
-
-    /**
-     * The location of the skins within the application resources directory.
-     */
-    private static final String SKINS_DIRECTORY = "/ui/skins";
-
-    /**
-     * The name of the directory where images are stored for this skin.
-     */
-    private static final String IMAGES_DIRECTORY = "/images";
-
-    /**
-     * Property tag for the default skin that is to be used for the web
-     * application.
-     */
-    private static final String SKIN_PROPERTY = "tool.ui.skin";
-
-    /**
-     * Property tag for the image directory inside the skin that is to be used
-     * for the web application.
-     */
-    private static final String IMAGEDIR_PROPERTY = "tool.ui.dir.image";
-
-    /**
-     * Property tag for the skin directory that is to be used for the web
-     * application.
-     */
-    private static final String SKINDIR_PROPERTY = "tool.ui.dir.skin";
-
-    /**
-     * Property tag for the css file that is to be used for the web 
application.
-     */
-    private static final String CSS_PROPERTY = "tool.ui.css";
-
-    /**
-     * Property tag for indicating if relative links are wanted for the web
-     * application.
-     */
-    private static final String RELATIVE_PROPERTY = "tool.ui.want.relative";
-
-    /**
-     * Default skin name. This name refers to a directory in the
-     * WEBAPP/resources/ui/skins directory. There is a file called skin.props
-     * which contains the name/value pairs to be made available via the skin.
-     */
-    public static final String SKIN_PROPERTY_DEFAULT = "default";
-
-    /**
-     * The skins directory, qualified by the resources directory (which is
-     * relative to the webapp context). This is used for constructing URIs and
-     * for retrieving skin files.
-     */
-    private String skinsDirectory;
-
-    /**
-     * The file within the skin directory that contains the name/value pairs 
for
-     * the skin.
-     */
-    private static final String SKIN_PROPS_FILE = "skin.props";
-
-    /**
-     * The file name for the skin style sheet.
-     */
-    private static final String DEFAULT_SKIN_CSS_FILE = "skin.css";
-
-    /**
-     * The servlet service.
-     */
-    private ServletService servletService;
-
-    /**
-     * The directory within the skin directory that contains the skin images.
-     */
-    private String imagesDirectory;
-
-    /**
-     * The name of the css file within the skin directory.
-     */
-    private String cssFile;
-
-    /**
-     * The flag that determines if the links that are returned are are absolute
-     * or relative.
-     */
-    private boolean wantRelative = false;
-
-    /**
-     * The skin Properties store.
-     */
-    private ConcurrentHashMap<String, Properties> skins = new 
ConcurrentHashMap<String, Properties>();
-
-    /**
-     * Refresh the service by clearing all skins.
-     */
-    @Override
-    public void refresh()
-    {
-        clearSkins();
-    }
-
-    /**
-     * Refresh a particular skin by clearing it.
-     *
-     * @param skinName the name of the skin to clear.
-     */
-    @Override
-    public void refresh(String skinName)
-    {
-        clearSkin(skinName);
-    }
-
-    /**
-     * Retrieve the Properties for a specific skin.  If they are not yet loaded
-     * they will be.  If the specified skin does not exist properties for the
-     * default skin configured for the webapp will be returned and an error
-     * level message will be written to the log.  If the webapp skin does not
-     * exist the default skin will be used and id that doesn't exist an empty
-     * Properties will be returned.
-     *
-     * @param skinName the name of the skin whose properties are to be
-     * retrieved.
-     * @return the Properties for the named skin or the properties for the
-     * default skin configured for the webapp if the named skin does not exist.
-     */
-    private Properties getSkinProperties(String skinName)
-    {
-        Properties skinProperties = skins.get(skinName);
-        return null != skinProperties ? skinProperties : loadSkin(skinName);
-    }
-
-    /**
-     * Retrieve a skin property from the named skin.  If the property is not
-     * defined in the named skin the value for the default skin will be
-     * provided.  If the named skin does not exist then the skin configured for
-     * the webapp will be used.  If the webapp skin does not exist the default
-     * skin will be used.  If the default skin does not exist then
-     * <code>null</code> will be returned.
-     *
-     * @param skinName the name of the skin to retrieve the property from.
-     * @param key the key to retrieve from the skin.
-     * @return the value of the property for the named skin (defaulting to the
-     * default skin), the webapp skin, the default skin or <code>null</code>,
-     * depending on whether or not the property or skins exist.
-     */
-    @Override
-    public String get(String skinName, String key)
-    {
-        Properties skinProperties = getSkinProperties(skinName);
-        return skinProperties.getProperty(key);
-    }
-
-    /**
-     * Retrieve a skin property from the default skin for the webapp.  If the
-     * property is not defined in the webapp skin the value for the default 
skin
-     * will be provided.  If the webapp skin does not exist the default skin
-     * will be used.  If the default skin does not exist then <code>null</code>
-     * will be returned.
-     *
-     * @param key the key to retrieve.
-     * @return the value of the property for the webapp skin (defaulting to the
-     * default skin), the default skin or <code>null</code>, depending on
-     * whether or not the property or skins exist.
-     */
-    @Override
-    public String get(String key)
-    {
-        return get(getWebappSkinName(), key);
-    }
-
-    /**
-     * Provide access to the list of available skin names.
-     *
-     * @return the available skin names.
-     */
-    @Override
-    public String[] getSkinNames()
-    {
-        File skinsDir = new File(servletService.getRealPath(skinsDirectory));
-        return skinsDir.list(DirectoryFileFilter.INSTANCE);
-    }
-
-    /**
-     * Clear the map of stored skins.
-     */
-    private void clearSkins()
-    {
-        skins.clear();
-        log.debug("All skins were cleared.");
-    }
-
-    /**
-     * Clear a particular skin from the map of stored skins.
-     *
-     * @param skinName the name of the skin to clear.
-     */
-    private void clearSkin(String skinName)
-    {
-        if (!skinName.equals(SKIN_PROPERTY_DEFAULT))
-        {
-            skins.remove(SKIN_PROPERTY_DEFAULT);
-        }
-        skins.remove(skinName);
-        log.debug("The skin \"" + skinName
-                + "\" was cleared (will also clear \"default\" skin).");
-    }
-
-    /**
-     * Load the specified skin.
-     *
-     * @param skinName the name of the skin to load.
-     * @return the Properties for the named skin if it exists, or the skin
-     * configured for the web application if it does not exist, or the default
-     * skin if that does not exist, or an empty Parameters object if even that
-     * cannot be found.
-     */
-    private Properties loadSkin(String skinName)
-    {
-        Properties defaultSkinProperties = null;
-
-        if (!StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
-        {
-            defaultSkinProperties = getSkinProperties(SKIN_PROPERTY_DEFAULT);
-        }
-
-        // The following line is okay even for default.
-        Properties skinProperties = new Properties(defaultSkinProperties);
-
-        StringBuilder sb = new StringBuilder();
-        sb.append('/').append(skinsDirectory);
-        sb.append('/').append(skinName);
-        sb.append('/').append(SKIN_PROPS_FILE);
-        if (log.isDebugEnabled())
-        {
-            log.debug("Loading selected skin from: " + sb.toString());
-        }
-
-        InputStream is = null;
-
-        try
-        {
-            // This will NPE if the directory associated with the skin does not
-            // exist, but it is handled correctly below.
-            is = servletService.getResourceAsStream(sb.toString());
-            skinProperties.load(is);
-        }
-        catch (Exception e)
-        {
-            log.error("Cannot load skin: " + skinName + ", from: "
-                    + sb.toString(), e);
-            if (!StringUtils.equals(skinName, getWebappSkinName())
-                    && !StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
-            {
-                log.error("Attempting to return the skin configured for "
-                        + "webapp instead of " + skinName);
-                return getSkinProperties(getWebappSkinName());
-            }
-            else if (!StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
-            {
-                log.error("Return the default skin instead of " + skinName);
-                return skinProperties; // Already contains the default skin.
-            }
-            else
-            {
-                log.error("No skins available - returning an empty 
Properties");
-                return new Properties();
-            }
-        }
-        finally
-        {
-            IOUtils.closeQuietly(is);
-        }
-
-        // Replace in skins HashMap
-        skins.put(skinName, skinProperties);
-
-        return skinProperties;
-    }
-
-    /**
-     * Get the name of the default skin name for the web application from the
-     * TurbineResources.properties file. If the property is not present the
-     * name of the default skin will be returned.  Note that the web 
application
-     * skin name may be something other than default, in which case its
-     * properties will default to the skin with the name "default".
-     *
-     * @return the name of the default skin for the web application.
-     */
-    @Override
-    public String getWebappSkinName()
-    {
-        return Turbine.getConfiguration()
-                .getString(SKIN_PROPERTY, SKIN_PROPERTY_DEFAULT);
-    }
-
-    /**
-     * Retrieve the URL for an image that is part of a skin. The images are
-     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
-     *
-     * <p>Use this if for some reason your server name, server scheme, or 
server
-     * port change on a per request basis. I'm not sure if this would happen in
-     * a load balanced situation. I think in most cases the image(String image)
-     * method would probably be enough, but I'm not absolutely positive.
-     *
-     * @param skinName the name of the skin to retrieve the image from.
-     * @param imageId the id of the image whose URL will be generated.
-     * @param serverData the serverData to use as the basis for the URL.
-     */
-    @Override
-    public String image(String skinName, String imageId, ServerData serverData)
-    {
-        return getSkinResource(serverData, skinName, imagesDirectory, imageId);
-    }
-
-    /**
-     * Retrieve the URL for an image that is part of a skin. The images are
-     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
-     *
-     * @param skinName the name of the skin to retrieve the image from.
-     * @param imageId the id of the image whose URL will be generated.
-     */
-    @Override
-    public String image(String skinName, String imageId)
-    {
-        return image(skinName, imageId, Turbine.getDefaultServerData());
-    }
-
-    /**
-     * Retrieve the URL for the style sheet that is part of a skin. The style 
is
-     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
-     * filename skin.css
-     *
-     * <p>Use this if for some reason your server name, server scheme, or 
server
-     * port change on a per request basis. I'm not sure if this would happen in
-     * a load balanced situation. I think in most cases the style() method 
would
-     * probably be enough, but I'm not absolutely positive.
-     *
-     * @param skinName the name of the skin to retrieve the style sheet from.
-     * @param serverData the serverData to use as the basis for the URL.
-     */
-    @Override
-    public String getStylecss(String skinName, ServerData serverData)
-    {
-        return getSkinResource(serverData, skinName, null, cssFile);
-    }
-
-    /**
-     * Retrieve the URL for the style sheet that is part of a skin. The style 
is
-     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
-     * filename skin.css
-     *
-     * @param skinName the name of the skin to retrieve the style sheet from.
-     */
-    @Override
-    public String getStylecss(String skinName)
-    {
-        return getStylecss(skinName, Turbine.getDefaultServerData());
-    }
-
-    /**
-     * Retrieve the URL for a given script that is part of a skin. The script 
is
-     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
-     *
-     * <p>Use this if for some reason your server name, server scheme, or 
server
-     * port change on a per request basis. I'm not sure if this would happen in
-     * a load balanced situation. I think in most cases the style() method 
would
-     * probably be enough, but I'm not absolutely positive.
-     *
-     * @param skinName the name of the skin to retrieve the image from.
-     * @param filename the name of the script file.
-     * @param serverData the serverData to use as the basis for the URL.
-     */
-    @Override
-    public String getScript(String skinName, String filename,
-            ServerData serverData)
-    {
-        return getSkinResource(serverData, skinName, null, filename);
-    }
-
-    /**
-     * Retrieve the URL for a given script that is part of a skin. The script 
is
-     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
-     *
-     * @param skinName the name of the skin to retrieve the image from.
-     * @param filename the name of the script file.
-     */
-    @Override
-    public String getScript(String skinName, String filename)
-    {
-        return getScript(skinName, filename, Turbine.getDefaultServerData());
-    }
-
-    private String stripSlashes(final String path)
-    {
-        if (StringUtils.isEmpty(path))
-        {
-            return "";
-        }
-
-        String ret = path;
-        int len = ret.length() - 1;
-
-        if (ret.charAt(len) == '/')
-        {
-            ret = ret.substring(0, len);
-        }
-
-        if (len > 0 && ret.charAt(0) == '/')
-        {
-            ret = ret.substring(1);
-        }
-
-        return ret;
-    }
-
-    /**
-     * Construct the URL to the skin resource.
-     *
-     * @param serverData the serverData to use as the basis for the URL.
-     * @param skinName the name of the skin.
-     * @param subDir the sub-directory in which the resource resides or
-     * <code>null</code> if it is in the root directory of the skin.
-     * @param resourceName the name of the resource to be retrieved.
-     * @return the path to the resource.
-     */
-    private String getSkinResource(ServerData serverData, String skinName,
-            String subDir, String resourceName)
-    {
-        StringBuilder sb = new StringBuilder(skinsDirectory);
-        sb.append("/").append(skinName);
-        if (subDir != null)
-        {
-            sb.append("/").append(subDir);
-        }
-        sb.append("/").append(stripSlashes(resourceName));
-
-        DataURI du = new DataURI(serverData);
-        du.setScriptName(sb.toString());
-        return wantRelative ? du.getRelativeLink() : du.getAbsoluteLink();
-    }
-
-    // ---- Service initilization ------------------------------------------
-
-    /**
-     * Initializes the service.
-     */
-    @Override
-    public void init() throws InitializationException
-    {
-        Configuration cfg = Turbine.getConfiguration();
-
-        servletService = 
(ServletService)TurbineServices.getInstance().getService(ServletService.SERVICE_NAME);
-        PullService pullService = 
(PullService)TurbineServices.getInstance().getService(PullService.SERVICE_NAME);
-        // Get the resources directory that is specified in the TR.props or
-        // default to "resources", relative to the webapp.
-        StringBuilder sb = new StringBuilder();
-        sb.append(stripSlashes(pullService.getResourcesDirectory()));
-        sb.append("/");
-        sb.append(stripSlashes(
-                cfg.getString(SKINDIR_PROPERTY, SKINS_DIRECTORY)));
-        skinsDirectory = sb.toString();
-
-        imagesDirectory = stripSlashes(
-                cfg.getString(IMAGEDIR_PROPERTY, IMAGES_DIRECTORY));
-        cssFile = cfg.getString(CSS_PROPERTY, DEFAULT_SKIN_CSS_FILE);
-        wantRelative = cfg.getBoolean(RELATIVE_PROPERTY, false);
-
-        setInit(true);
-    }
-
-    /**
-     * Returns to uninitialized state.
-     */
-    @Override
-    public void shutdown()
-    {
-        clearSkins();
-        setInit(false);
-    }
-}
+package org.apache.turbine.services.ui;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.filefilter.DirectoryFileFilter;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.turbine.Turbine;
+import org.apache.turbine.services.InitializationException;
+import org.apache.turbine.services.TurbineBaseService;
+import org.apache.turbine.services.TurbineServices;
+import org.apache.turbine.services.pull.PullService;
+import org.apache.turbine.services.pull.tools.UITool;
+import org.apache.turbine.services.servlet.ServletService;
+import org.apache.turbine.util.ServerData;
+import org.apache.turbine.util.uri.DataURI;
+
+/**
+ * The UI service provides for shared access to User Interface (skin) files,
+ * as well as the ability for non-default skin files to inherit properties from
+ * a default skin.  Use TurbineUI to access skin properties from your screen
+ * classes and action code. UITool is provided as a pull tool for accessing
+ * skin properties from your templates.
+ *
+ * @author <a href="mailto:[email protected]";>Jason van Zyl</a>
+ * @author <a href="mailto:[email protected]";>James Coltman</a>
+ * @author <a href="mailto:[email protected]";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:[email protected]";>Scott Eade</a>
+ * @author <a href="[email protected]">Thomas Vandahl</a>
+ * @version $Id$
+ * @see UIService
+ * @see UITool
+ */
+public class TurbineUIService
+        extends TurbineBaseService
+        implements UIService
+{
+    /** Logging. */
+    private static Log log = LogFactory.getLog(TurbineUIService.class);
+
+    /**
+     * The location of the skins within the application resources directory.
+     */
+    private static final String SKINS_DIRECTORY = "/ui/skins";
+
+    /**
+     * The name of the directory where images are stored for this skin.
+     */
+    private static final String IMAGES_DIRECTORY = "/images";
+
+    /**
+     * Property tag for the default skin that is to be used for the web
+     * application.
+     */
+    private static final String SKIN_PROPERTY = "tool.ui.skin";
+
+    /**
+     * Property tag for the image directory inside the skin that is to be used
+     * for the web application.
+     */
+    private static final String IMAGEDIR_PROPERTY = "tool.ui.dir.image";
+
+    /**
+     * Property tag for the skin directory that is to be used for the web
+     * application.
+     */
+    private static final String SKINDIR_PROPERTY = "tool.ui.dir.skin";
+
+    /**
+     * Property tag for the css file that is to be used for the web 
application.
+     */
+    private static final String CSS_PROPERTY = "tool.ui.css";
+
+    /**
+     * Property tag for indicating if relative links are wanted for the web
+     * application.
+     */
+    private static final String RELATIVE_PROPERTY = "tool.ui.want.relative";
+
+    /**
+     * Default skin name. This name refers to a directory in the
+     * WEBAPP/resources/ui/skins directory. There is a file called skin.props
+     * which contains the name/value pairs to be made available via the skin.
+     */
+    public static final String SKIN_PROPERTY_DEFAULT = "default";
+
+    /**
+     * The skins directory, qualified by the resources directory (which is
+     * relative to the webapp context). This is used for constructing URIs and
+     * for retrieving skin files.
+     */
+    private String skinsDirectory;
+
+    /**
+     * The file within the skin directory that contains the name/value pairs 
for
+     * the skin.
+     */
+    private static final String SKIN_PROPS_FILE = "skin.props";
+
+    /**
+     * The file name for the skin style sheet.
+     */
+    private static final String DEFAULT_SKIN_CSS_FILE = "skin.css";
+
+    /**
+     * The servlet service.
+     */
+    private ServletService servletService;
+
+    /**
+     * The directory within the skin directory that contains the skin images.
+     */
+    private String imagesDirectory;
+
+    /**
+     * The name of the css file within the skin directory.
+     */
+    private String cssFile;
+
+    /**
+     * The flag that determines if the links that are returned are are absolute
+     * or relative.
+     */
+    private boolean wantRelative = false;
+
+    /**
+     * The skin Properties store.
+     */
+    private ConcurrentHashMap<String, Properties> skins = new 
ConcurrentHashMap<String, Properties>();
+
+    /**
+     * Refresh the service by clearing all skins.
+     */
+    @Override
+    public void refresh()
+    {
+        clearSkins();
+    }
+
+    /**
+     * Refresh a particular skin by clearing it.
+     *
+     * @param skinName the name of the skin to clear.
+     */
+    @Override
+    public void refresh(String skinName)
+    {
+        clearSkin(skinName);
+    }
+
+    /**
+     * Retrieve the Properties for a specific skin.  If they are not yet loaded
+     * they will be.  If the specified skin does not exist properties for the
+     * default skin configured for the webapp will be returned and an error
+     * level message will be written to the log.  If the webapp skin does not
+     * exist the default skin will be used and id that doesn't exist an empty
+     * Properties will be returned.
+     *
+     * @param skinName the name of the skin whose properties are to be
+     * retrieved.
+     * @return the Properties for the named skin or the properties for the
+     * default skin configured for the webapp if the named skin does not exist.
+     */
+    private Properties getSkinProperties(String skinName)
+    {
+        Properties skinProperties = skins.get(skinName);
+        return null != skinProperties ? skinProperties : loadSkin(skinName);
+    }
+
+    /**
+     * Retrieve a skin property from the named skin.  If the property is not
+     * defined in the named skin the value for the default skin will be
+     * provided.  If the named skin does not exist then the skin configured for
+     * the webapp will be used.  If the webapp skin does not exist the default
+     * skin will be used.  If the default skin does not exist then
+     * <code>null</code> will be returned.
+     *
+     * @param skinName the name of the skin to retrieve the property from.
+     * @param key the key to retrieve from the skin.
+     * @return the value of the property for the named skin (defaulting to the
+     * default skin), the webapp skin, the default skin or <code>null</code>,
+     * depending on whether or not the property or skins exist.
+     */
+    @Override
+    public String get(String skinName, String key)
+    {
+        Properties skinProperties = getSkinProperties(skinName);
+        return skinProperties.getProperty(key);
+    }
+
+    /**
+     * Retrieve a skin property from the default skin for the webapp.  If the
+     * property is not defined in the webapp skin the value for the default 
skin
+     * will be provided.  If the webapp skin does not exist the default skin
+     * will be used.  If the default skin does not exist then <code>null</code>
+     * will be returned.
+     *
+     * @param key the key to retrieve.
+     * @return the value of the property for the webapp skin (defaulting to the
+     * default skin), the default skin or <code>null</code>, depending on
+     * whether or not the property or skins exist.
+     */
+    @Override
+    public String get(String key)
+    {
+        return get(getWebappSkinName(), key);
+    }
+
+    /**
+     * Provide access to the list of available skin names.
+     *
+     * @return the available skin names.
+     */
+    @Override
+    public String[] getSkinNames()
+    {
+        File skinsDir = new File(servletService.getRealPath(skinsDirectory));
+        return skinsDir.list(DirectoryFileFilter.INSTANCE);
+    }
+
+    /**
+     * Clear the map of stored skins.
+     */
+    private void clearSkins()
+    {
+        skins.clear();
+        log.debug("All skins were cleared.");
+    }
+
+    /**
+     * Clear a particular skin from the map of stored skins.
+     *
+     * @param skinName the name of the skin to clear.
+     */
+    private void clearSkin(String skinName)
+    {
+        if (!skinName.equals(SKIN_PROPERTY_DEFAULT))
+        {
+            skins.remove(SKIN_PROPERTY_DEFAULT);
+        }
+        skins.remove(skinName);
+        log.debug("The skin \"" + skinName
+                + "\" was cleared (will also clear \"default\" skin).");
+    }
+
+    /**
+     * Load the specified skin.
+     *
+     * @param skinName the name of the skin to load.
+     * @return the Properties for the named skin if it exists, or the skin
+     * configured for the web application if it does not exist, or the default
+     * skin if that does not exist, or an empty Parameters object if even that
+     * cannot be found.
+     */
+    private Properties loadSkin(String skinName)
+    {
+        Properties defaultSkinProperties = null;
+
+        if (!StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
+        {
+            defaultSkinProperties = getSkinProperties(SKIN_PROPERTY_DEFAULT);
+        }
+
+        // The following line is okay even for default.
+        Properties skinProperties = new Properties(defaultSkinProperties);
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('/').append(skinsDirectory);
+        sb.append('/').append(skinName);
+        sb.append('/').append(SKIN_PROPS_FILE);
+        if (log.isDebugEnabled())
+        {
+            log.debug("Loading selected skin from: " + sb.toString());
+        }
+
+        InputStream is = null;
+
+        try
+        {
+            // This will NPE if the directory associated with the skin does not
+            // exist, but it is handled correctly below.
+            is = servletService.getResourceAsStream(sb.toString());
+            skinProperties.load(is);
+        }
+        catch (Exception e)
+        {
+            log.error("Cannot load skin: " + skinName + ", from: "
+                    + sb.toString(), e);
+            if (!StringUtils.equals(skinName, getWebappSkinName())
+                    && !StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
+            {
+                log.error("Attempting to return the skin configured for "
+                        + "webapp instead of " + skinName);
+                return getSkinProperties(getWebappSkinName());
+            }
+            else if (!StringUtils.equals(skinName, SKIN_PROPERTY_DEFAULT))
+            {
+                log.error("Return the default skin instead of " + skinName);
+                return skinProperties; // Already contains the default skin.
+            }
+            else
+            {
+                log.error("No skins available - returning an empty 
Properties");
+                return new Properties();
+            }
+        }
+        finally
+        {
+            IOUtils.closeQuietly(is);
+        }
+
+        // Replace in skins HashMap
+        skins.put(skinName, skinProperties);
+
+        return skinProperties;
+    }
+
+    /**
+     * Get the name of the default skin name for the web application from the
+     * TurbineResources.properties file. If the property is not present the
+     * name of the default skin will be returned.  Note that the web 
application
+     * skin name may be something other than default, in which case its
+     * properties will default to the skin with the name "default".
+     *
+     * @return the name of the default skin for the web application.
+     */
+    @Override
+    public String getWebappSkinName()
+    {
+        return Turbine.getConfiguration()
+                .getString(SKIN_PROPERTY, SKIN_PROPERTY_DEFAULT);
+    }
+
+    /**
+     * Retrieve the URL for an image that is part of a skin. The images are
+     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
+     *
+     * <p>Use this if for some reason your server name, server scheme, or 
server
+     * port change on a per request basis. I'm not sure if this would happen in
+     * a load balanced situation. I think in most cases the image(String image)
+     * method would probably be enough, but I'm not absolutely positive.
+     *
+     * @param skinName the name of the skin to retrieve the image from.
+     * @param imageId the id of the image whose URL will be generated.
+     * @param serverData the serverData to use as the basis for the URL.
+     */
+    @Override
+    public String image(String skinName, String imageId, ServerData serverData)
+    {
+        return getSkinResource(serverData, skinName, imagesDirectory, imageId);
+    }
+
+    /**
+     * Retrieve the URL for an image that is part of a skin. The images are
+     * stored in the WEBAPP/resources/ui/skins/[SKIN]/images directory.
+     *
+     * @param skinName the name of the skin to retrieve the image from.
+     * @param imageId the id of the image whose URL will be generated.
+     */
+    @Override
+    public String image(String skinName, String imageId)
+    {
+        return image(skinName, imageId, Turbine.getDefaultServerData());
+    }
+
+    /**
+     * Retrieve the URL for the style sheet that is part of a skin. The style 
is
+     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
+     * filename skin.css
+     *
+     * <p>Use this if for some reason your server name, server scheme, or 
server
+     * port change on a per request basis. I'm not sure if this would happen in
+     * a load balanced situation. I think in most cases the style() method 
would
+     * probably be enough, but I'm not absolutely positive.
+     *
+     * @param skinName the name of the skin to retrieve the style sheet from.
+     * @param serverData the serverData to use as the basis for the URL.
+     */
+    @Override
+    public String getStylecss(String skinName, ServerData serverData)
+    {
+        return getSkinResource(serverData, skinName, null, cssFile);
+    }
+
+    /**
+     * Retrieve the URL for the style sheet that is part of a skin. The style 
is
+     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory with the
+     * filename skin.css
+     *
+     * @param skinName the name of the skin to retrieve the style sheet from.
+     */
+    @Override
+    public String getStylecss(String skinName)
+    {
+        return getStylecss(skinName, Turbine.getDefaultServerData());
+    }
+
+    /**
+     * Retrieve the URL for a given script that is part of a skin. The script 
is
+     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
+     *
+     * <p>Use this if for some reason your server name, server scheme, or 
server
+     * port change on a per request basis. I'm not sure if this would happen in
+     * a load balanced situation. I think in most cases the style() method 
would
+     * probably be enough, but I'm not absolutely positive.
+     *
+     * @param skinName the name of the skin to retrieve the image from.
+     * @param filename the name of the script file.
+     * @param serverData the serverData to use as the basis for the URL.
+     */
+    @Override
+    public String getScript(String skinName, String filename,
+            ServerData serverData)
+    {
+        return getSkinResource(serverData, skinName, null, filename);
+    }
+
+    /**
+     * Retrieve the URL for a given script that is part of a skin. The script 
is
+     * stored in the WEBAPP/resources/ui/skins/[SKIN] directory.
+     *
+     * @param skinName the name of the skin to retrieve the image from.
+     * @param filename the name of the script file.
+     */
+    @Override
+    public String getScript(String skinName, String filename)
+    {
+        return getScript(skinName, filename, Turbine.getDefaultServerData());
+    }
+
+    private String stripSlashes(final String path)
+    {
+        if (StringUtils.isEmpty(path))
+        {
+            return "";
+        }
+
+        String ret = path;
+        int len = ret.length() - 1;
+
+        if (ret.charAt(len) == '/')
+        {
+            ret = ret.substring(0, len);
+        }
+
+        if (len > 0 && ret.charAt(0) == '/')
+        {
+            ret = ret.substring(1);
+        }
+
+        return ret;
+    }
+
+    /**
+     * Construct the URL to the skin resource.
+     *
+     * @param serverData the serverData to use as the basis for the URL.
+     * @param skinName the name of the skin.
+     * @param subDir the sub-directory in which the resource resides or
+     * <code>null</code> if it is in the root directory of the skin.
+     * @param resourceName the name of the resource to be retrieved.
+     * @return the path to the resource.
+     */
+    private String getSkinResource(ServerData serverData, String skinName,
+            String subDir, String resourceName)
+    {
+        StringBuilder sb = new StringBuilder(skinsDirectory);
+        sb.append("/").append(skinName);
+        if (subDir != null)
+        {
+            sb.append("/").append(subDir);
+        }
+        sb.append("/").append(stripSlashes(resourceName));
+
+        DataURI du = new DataURI(serverData);
+        du.setScriptName(sb.toString());
+        return wantRelative ? du.getRelativeLink() : du.getAbsoluteLink();
+    }
+
+    // ---- Service initilization ------------------------------------------
+
+    /**
+     * Initializes the service.
+     */
+    @Override
+    public void init() throws InitializationException
+    {
+        Configuration cfg = Turbine.getConfiguration();
+
+        servletService = 
(ServletService)TurbineServices.getInstance().getService(ServletService.SERVICE_NAME);
+        PullService pullService = 
(PullService)TurbineServices.getInstance().getService(PullService.SERVICE_NAME);
+        // Get the resources directory that is specified in the TR.props or
+        // default to "resources", relative to the webapp.
+        StringBuilder sb = new StringBuilder();
+        sb.append(stripSlashes(pullService.getResourcesDirectory()));
+        sb.append("/");
+        sb.append(stripSlashes(
+                cfg.getString(SKINDIR_PROPERTY, SKINS_DIRECTORY)));
+        skinsDirectory = sb.toString();
+
+        imagesDirectory = stripSlashes(
+                cfg.getString(IMAGEDIR_PROPERTY, IMAGES_DIRECTORY));
+        cssFile = cfg.getString(CSS_PROPERTY, DEFAULT_SKIN_CSS_FILE);
+        wantRelative = cfg.getBoolean(RELATIVE_PROPERTY, false);
+
+        setInit(true);
+    }
+
+    /**
+     * Returns to uninitialized state.
+     */
+    @Override
+    public void shutdown()
+    {
+        clearSkins();
+        setInit(false);
+    }
+}


Reply via email to