/*
 * Copyright 2005 Joe Walker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.directwebremoting.jaxer.impl;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.directwebremoting.extend.Creator;
import org.directwebremoting.impl.DefaultCreatorManager;
import org.directwebremoting.util.LocalUtil;
import org.directwebremoting.util.Messages;

/**
 * This is a modification of {@link DefaultCreatorManager} that attempts to do
 * a second round of configuration to allow direct access to any classes in the
 * system using a script name something like: creator/com/example/ClassName
 * <p><strong>WARNING:</strong> This class fundamentally breaks the DWR promise
 * of "we won't touch any of your code without your express permission". You
 * should only configure this class if you fully understand the implications of
 * doing so.
 * <p>This class was created to allow remoting between Jaxer and DWR for scripts
 * marked <code>runat="server"</code>. This should ensure that the exported
 * classes are not available to the outside world.
 * @author Joe Walker [joe at getahead dot ltd dot uk]
 */
public class WideOpenCreatorManager extends DefaultCreatorManager
{
    /* (non-Javadoc)
     * @see org.directwebremoting.CreatorManager#getCreator(java.lang.String)
     */
    @Override
    public Creator getCreator(String scriptName, boolean includeHidden) throws SecurityException
    {
        Creator creator = creators.get(scriptName);

        if (creator == null)
        {
            creator = shortNames.get(scriptName);
        }

        if (creator == null)
        {
            // So there is no creator by the given name. Next we try the more
            // verbose version where the script name is something like:
            // creator/com/example/ClassName
            String[] parts = scriptName.split("/", 2);
            if (parts.length == 1)
            {
                log.warn("Malformed scriptName: " + scriptName);
                throw new SecurityException("Malformed scriptName");
            }

            String className = parts[1];
            String creatorName = parts[0];
            try
            {
                // This is roughly equivalent to:
                // addCreator(className, creatorName, { });

                Class<? extends Creator> clazz = creatorTypes.get(creatorName);
                if (clazz == null)
                {
                    log.error("Missing creator: " + creatorName + " (while initializing creator for: " + className + ".js)");
                    throw new SecurityException("Missing creator");
                }

                creator = clazz.newInstance();

                // Nasty! Each creator has a different set of init params. The
                // 'new' creator needs a class param, but the spring creator
                // needs a 'bean' param. We only have enough for a single param
                // in the URL and we don't know what it should be called. So
                // this code is tied to the new creator. Yeulch
                Map<String, String> params = new HashMap<String, String>();
                params.put("class", className);
                params.put("scope", "application");

                LocalUtil.setParams(creator, params, ignore);
                creator.setProperties(params);
                addCreator(scriptName, creator);
                shortNames.put(creator.getJavascript(), creator);

                creator = creators.get(scriptName);
            }
            catch (Exception ex)
            {
                log.warn("Error adding creator: " + scriptName, ex);
                throw new SecurityException("Error adding creator");
            }
        }

        if (creator.isHidden() && !includeHidden)
        {
            log.warn("Attempt made to get hidden class with name: " + scriptName + " while includeHidden=false");
            throw new SecurityException(Messages.getString("DefaultCreatorManager.MissingName", scriptName));
        }

        return creator;
    }

    /**
     * We index creators by short name as well as full name
     */
    private Map<String, Creator> shortNames = new HashMap<String, Creator>();

    /**
     * The log stream
     */
    private static final Log log = LogFactory.getLog(WideOpenCreatorManager.class);
}

@@ -3805,19 +3805,14 @@
 %22, %22
-application
+script
 %22);%0A

Change to make default scope "script" for Jaxer