/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *     "Apache Jetspeed" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache" or
 *    "Apache Jetspeed", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package org.apache.jetspeed.services.registry;

import java.io.File;
import java.io.FileReader;

import java.util.Vector;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Map;

// Junit imports
import junit.framework.Test;
import junit.framework.TestSuite;

//castor support
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.mapping.Mapping;
import org.xml.sax.InputSource;

// Jetspeed imports
import org.apache.jetspeed.test.JetspeedTestCase;
import org.apache.jetspeed.om.registry.CachedParameter;
import org.apache.jetspeed.om.registry.Category;
import org.apache.jetspeed.om.registry.ContentURL;
import org.apache.jetspeed.om.registry.MetaInfo;
import org.apache.jetspeed.om.registry.Parameter;
import org.apache.jetspeed.om.registry.PortletEntry;
import org.apache.jetspeed.om.registry.SecurityAccess;
import org.apache.jetspeed.om.registry.SecurityAllow;
import org.apache.jetspeed.om.registry.SecurityEntry;
import org.apache.jetspeed.om.SecurityReference;

// Turbine imports
import org.apache.turbine.util.TurbineConfig;
import org.apache.turbine.util.StringUtils;

/**
 * TestMarshallRegistry
 *
 * @author <a href="taylor@apache.org">David Sean Taylor</a>
 * @version $Id: TestMarshallRegistry.java,v 1.8 2003/08/08 18:28:03 morciuch Exp $
 */

public class TestMarshallRegistry extends JetspeedTestCase
{
    /**
     * Defines the testcase name for JUnit.
     *
     * @param name the testcase's name.
     */
    public TestMarshallRegistry(String name)
    {
        super(name);
    }

    /**
     * Start the tests.
     *
     * @param args the arguments. Not used
     */
    public static void main(String args[])
    {
        junit.awtui.TestRunner.main(new String[] { TestMarshallRegistry.class.getName() });
    }

    public void setup()
    {
        System.out.println("Setup: Testing marshalling of Registry");
     }

    /**
     * Creates the test suite.
     *
     * @return a test suite (<code>TestSuite</code>) that includes all methods
     *         starting with "test"
     */
    public static Test suite()
    {
        // All methods starting with "test" will be executed in the test suite.
        return new TestSuite(TestMarshallRegistry.class);
    }

    private String getMappingFileName()
    {
        return "../webapp/WEB-INF/conf/registry.xml";
    }

    /**
     * Tests unmarshaling registry fragment
     * @throws Exception
     */
    public void testUnmarshallRegistry() throws Exception
    {
        System.out.println("Testing marshalling of Registry");

        String xregFile = "../webapp/WEB-INF/psml/test/testcase-2.xreg";

        Mapping mapping = null;
        String mapFile = getMappingFileName();
        File map = new File(mapFile);
        if (map.exists() && map.isFile() && map.canRead())
        {
            try
            {
                FileReader reader = new FileReader(xregFile);
                mapping = new Mapping();
                InputSource is = new InputSource(new FileReader(map));
                is.setSystemId(mapFile);
                mapping.loadMapping(is);
                Unmarshaller unmarshaller = new Unmarshaller(mapping);
                RegistryFragment fragment = (RegistryFragment) unmarshaller.unmarshal(reader);
                assertNotNull(fragment);
                Vector portlets = fragment.getPortlets();

                // test abstract

                PortletEntry rss = (PortletEntry) portlets.elementAt(1);
                assertNotNull(rss);
                assertTrue(rss.getName().equals("RSS"));
                assertTrue(!rss.isHidden());
                assertTrue(rss.getType().equals("abstract"));
                assertNull(rss.getParent());
                assertTrue(!rss.isApplication());
                assertTrue(rss.getClassname().equals("org.apache.jetspeed.portal.portlets.NewRSSPortlet"));
                // params
                Iterator it = rss.getParameterNames();
                HashMap mapParams = new HashMap();
                while (it.hasNext())
                {
                    String name = (String) it.next();
                    Parameter p = rss.getParameter(name);
                    assertNotNull(p);
                    //System.out.println("PARAM:" + p.getName() + " = " + p.getValue());
                    mapParams.put(p.getName(), p);
                }
                assertTrue(mapParams.containsKey("showtitle"));
                assertTrue(mapParams.containsKey("stylesheet"));
                assertTrue(mapParams.containsKey("itemdisplayed"));

                // test ref
                PortletEntry hack = (PortletEntry) portlets.elementAt(2);
                assertNotNull(hack);
                assertTrue(hack.getName().equals("XMLHack"));
                assertTrue(hack.isHidden());
                assertTrue(hack.getType().equals("ref"));
                assertTrue(hack.getParent().equals("RSS"));
                assertTrue(!hack.isApplication());
                assertTrue(hack.getTitle().equals("XMLHack Title"));
                assertTrue(hack.getDescription().equals("XMLHack Description"));
                assertTrue(hack.getMetaInfo().getTitle().equals("XMLHack Title"));
                assertTrue(hack.getMetaInfo().getDescription().equals("XMLHack Description"));
                assertTrue(hack.getClassname().equals("org.apache.jetspeed.portal.portlets.NewRSSPortlet"));

                mapParams.clear();
                it = hack.getParameterNames();
                while (it.hasNext())
                {
                    String name = (String) it.next();
                    Parameter p = hack.getParameter(name);
                    assertNotNull(p);
                    //System.out.println("HACK PARAM:" + p.getName() + " = " + p.getValue());
                    mapParams.put(p.getName(), p);
                }
                assertTrue(mapParams.containsKey("showtitle"));
                assertTrue(mapParams.containsKey("stylesheet"));
                assertTrue(mapParams.containsKey("itemdisplayed"));
                assertTrue(mapParams.containsKey("HACK"));
                Parameter p = (Parameter) mapParams.get("HACK");
                assertTrue(p.getValue().equals("hacker"));
                Parameter p2 = (Parameter) mapParams.get("showtitle");
                MetaInfo p2m = p2.getMetaInfo();
                assertTrue(p2m.getTitle().equals("Show title description ?"));
                assertTrue(p2.getTitle().equals("Show title description ?"));
                Map pMap = hack.getParameterMap();
                String v15 = (String) pMap.get("itemdisplayed");
                assertTrue(v15.equals("15"));

                // test falling back on meta info

                PortletEntry mp = (PortletEntry) portlets.elementAt(5);
                assertNotNull(mp);
                assertTrue(mp.getName().equals("MetaTest"));
                assertTrue(mp.getType().equals("ref"));
                assertTrue(mp.getParent().equals("AdminScreen"));
                assertTrue(mp.getClassname().equals("org.apache.jetspeed.portal.portlets.TurbineScreenPortlet"));
                String title = mp.getTitle();
                assertNotNull(title);
                assertTrue(title.equals("Turbine Screen in a portlet"));
                assertTrue(mp.getDescription().equals("We put the Admin Screen in a portlet."));
                MetaInfo meta = mp.getMetaInfo();
                assertNotNull(meta);
                assertTrue(mp.getMetaInfo().getTitle().equals("Turbine Screen in a portlet"));
                assertTrue(meta.getDescription().equals("We put the Admin Screen in a portlet."));

                // media type
                Iterator mpi = mp.listMediaTypes();
                assertNotNull(mpi);
                HashMap mpMap = new HashMap();
                while (mpi.hasNext())
                {
                    String s = (String) mpi.next();
                    mpMap.put(s, s);
                }
                assertTrue(mpMap.containsKey("html"));
                assertTrue(mpMap.containsKey("wml"));
                assertTrue(mpMap.containsKey("xml"));
                assertTrue(mp.hasMediaType("wml"));

                PortletEntry mt = (PortletEntry) portlets.elementAt(6);
                assertNotNull(mt);
                assertTrue(mt.getName().equals("NoMediaType"));
                assertTrue(mt.getType().equals("ref"));
                Iterator mti = mt.listMediaTypes();
                assertNotNull(mti);
                assertTrue(mti.hasNext());
                String s = (String) mti.next();
                assertTrue(s.equals("html"));

                assertTrue(hack.getURL().equals("http://www.xmlhack.com/rss.php"));
                assertTrue(hack.isCachedOnURL());

                PortletEntry keytest = (PortletEntry) portlets.elementAt(7);
                assertNotNull(keytest);
                assertTrue(keytest.getName().equals("KeyTest"));
                assertTrue(keytest.getType().equals("ref"));
                it = keytest.getParameterNames();
                mpMap.clear();
                while (it.hasNext())
                {
                    String name = (String) it.next();
                    CachedParameter cp = keytest.getCachedParameter(name);
                    mpMap.put(cp.getName(), cp);
                    //System.out.println("param = " + cp.getName() + "," + cp.getValue());
                    //System.out.println("keys = " + cp.isCachedOnName() + "," + cp.isCachedOnValue());

                }
                assertTrue(keytest.isCachedOnURL() == false);
                CachedParameter cp = (CachedParameter) mpMap.get("newsid");
                assertNotNull(cp);
                assertTrue(cp.isCachedOnName() == false);
                assertTrue(cp.isCachedOnValue() == true);
                cp = (CachedParameter) mpMap.get("sportsid");
                assertNotNull(cp);
                assertTrue(cp.isCachedOnName() == true);
                assertTrue(cp.isCachedOnValue() == false);
                cp = (CachedParameter) mpMap.get("contact2");
                assertNotNull(cp);
                assertTrue(cp.isCachedOnName() == true);
                assertTrue(cp.isCachedOnValue() == true);
                cp = (CachedParameter) mpMap.get("showtitle");
                assertNotNull(cp);
                assertTrue(cp.isCachedOnName() == true);
                assertTrue(cp.isCachedOnValue() == true);

                // categories
                PortletEntry feeder = (PortletEntry) portlets.elementAt(3);
                assertNotNull(feeder);
                assertTrue(feeder.getName().equals("Feeder"));
                assertTrue(feeder.getType().equals("ref"));
                Iterator fi = feeder.listCategories();
                Category cat = (Category) fi.next();
                assertTrue(cat.getName().equals("news.world.politics"));
                assertTrue(cat.getGroup().equals("news"));
                assertTrue(feeder.hasCategory("news.world.politics", "news"));
                feeder.addCategory("news.us.economy");
                assertTrue(feeder.hasCategory("news.us.economy"));
                feeder.removeCategory("news.us.economy");
                assertTrue(!feeder.hasCategory("news.us.economy"));
                /*
                Iterator fi = feeder.listCategories();
                    Category cat = (Category)fi.next();
                    System.out.println("cat = " + cat.getName());
                    System.out.println("cat.group = " + cat.getGroup());
                }
                */
            }
            catch (Exception e)
            {
                String errmsg = "Error in xreg mapping creation: " + e.toString();
               // e.printStackTrace();
               assertNotNull(errmsg, null);
            }
        }
        else
        {
            String errmsg = "Registy Mapping not found or not a file or unreadable: ";
            System.err.println(errmsg);
            assertNotNull(errmsg, null);
        }
    }


    /**
     * Tests unmarshaling registry fragment
     * @throws Exception
     */
    public void testUnmarshallSecurityRegistry() throws Exception
    {
        boolean entryFound = false;
        System.out.println("Testing marshalling of Registry security-entry");

        String xregFile = "../webapp/WEB-INF/psml/test/testcase-security.xreg";

        Mapping mapping = null;
        String mapFile = getMappingFileName();
        File map = new File(mapFile);
        if (map.exists() && map.isFile() && map.canRead())
        {
            FileReader reader = new FileReader(xregFile);
            mapping = new Mapping();
            InputSource is = new InputSource(new FileReader(map));
            is.setSystemId(mapFile);
            mapping.loadMapping(is);
            Unmarshaller unmarshaller = new Unmarshaller(mapping);
            RegistryFragment fragment = (RegistryFragment) unmarshaller.unmarshal(reader);
            assertNotNull(fragment);
            Vector securityEntries = fragment.getSecurityEntries();
            assertTrue("Security Entries exist", !securityEntries.isEmpty());

            // test abstract
            SecurityEntry securityEntry = (SecurityEntry) securityEntries.firstElement();
            assertNotNull("Got first Security Entry", securityEntry);
            assertTrue("Getting expect security entry", securityEntry.getName().equals("basic_testcase"));

            // Get the action
            Vector securityAccesses = securityEntry.getAccesses();
            assertNotNull("Got SecurityAccesses", securityAccesses);
            SecurityAccess securityAccess = (SecurityAccess) securityAccesses.firstElement();
            assertNotNull("Got SecurityAccess", securityAccess);
            assertEquals("Verify action", "view", securityAccess.getAction());

            // Get allows
            Vector securityAllows = securityAccess.getAllows();
            assertNotNull("Got SecurityAllows", securityAllows);
            SecurityAllow securityAllow = (SecurityAllow) securityAllows.firstElement();
            assertNotNull("Got SecurityAllow", securityAllow);
            assertEquals("Verify role", "clerk", securityAllow.getRole());
            assertNull("Verify user" , securityAllow.getUser());

            securityAllow = (SecurityAllow) securityAllows.elementAt(1);
            assertNotNull("Got SecurityAllow", securityAllow);
            assertNull("Verify role", securityAllow.getRole());
            assertEquals("Verify user", "joe", securityAllow.getUser());

            securityAllow = (SecurityAllow) securityAllows.elementAt(2);
            assertNotNull("Got SecurityAllow", securityAllow);
            assertEquals("Verify role", "manager", securityAllow.getRole());
            assertEquals("Verify user", "fred", securityAllow.getUser());

            // test allows
            assertEquals("clerk role can view", true, securityEntry.allowsRole("clerk", "view"));
            assertEquals("manager role can view", true, securityEntry.allowsRole("manager", "view"));
            assertEquals("anonymous role can NOT view", false, securityEntry.allowsRole("anonymous", "view"));
            assertEquals("fred user can view", true, securityEntry.allowsUser("fred", "view"));
            assertEquals("joe user can view", true, securityEntry.allowsUser("joe", "view"));
            assertEquals("anonymous user can NOT view", false, securityEntry.allowsUser("anonymous", "view"));

            // Customize has <allow-id user="*"/>
            assertEquals("clerk role can NOT customize", false, securityEntry.allowsRole("clerk", "customize"));
            assertEquals("joe user can customize", true, securityEntry.allowsUser("joe", "customize"));

            // Minimize has no <allows-if .../>
            assertEquals("clerk role can NOT minimize", true, securityEntry.allowsRole("clerk", "minimize"));
            assertEquals("joe user can NOT minimize", true, securityEntry.allowsUser("joe", "minimize"));

            // Maximixe is not defined
            assertEquals("clerk role can NOT maximize", false, securityEntry.allowsRole("clerk", "maximize"));
            assertEquals("joe user can NOT maximize", false, securityEntry.allowsUser("joe", "maximize"));

            // Test the wide-open entry
            entryFound = false;
            for (Iterator securityIterator = securityEntries.iterator(); securityIterator.hasNext();)
            {
                securityEntry = (SecurityEntry) securityIterator.next();
                if (securityEntry.getName().equals("wide_open") == true)
                {
                    entryFound = true;
                    assertEquals("any role is NOT allowed", false, securityEntry.allowsRole("customer", "do_any_thing"));
                    assertEquals("any user is allowed", true, securityEntry.allowsUser("joe_customer", "do_any_thing"));
                }
            }
            assertTrue("Found wide_open security entry", entryFound);

            // Test the owner-only entry
            entryFound = false;
            for (Iterator securityIterator = securityEntries.iterator(); securityIterator.hasNext();)
            {
                securityEntry = (SecurityEntry) securityIterator.next();
                if (securityEntry.getName().equals("owner_only") == true)
                {
                    entryFound = true;
                    assertEquals("User joe_customer is not allowed", false,
                                 securityEntry.allowsUser("joe_customer", "do_any_thing"));
                    assertEquals("User joe_customer is not allowed", false,
                                 securityEntry.allowsUser("joe_customer", "do_any_thing", "joe_owner"));
                    assertEquals("User joe_owner is allowed", true,
                                 securityEntry.allowsUser("joe_owner", "do_any_thing", "joe_owner"));
                }
            }
            assertTrue("Found owner_only security entry", entryFound);
        }
    }

    public void testUnmarshallSecurityReference() throws Exception
    {
        System.out.println("Testing marshalling of Registry security-ref");

        String xregFile = "../webapp/WEB-INF/psml/test/testcase-security.xreg";

        Mapping mapping = null;
        String mapFile = getMappingFileName();
        File map = new File(mapFile);
        if (map.exists() && map.isFile() && map.canRead())
        {
            FileReader reader = new FileReader(xregFile);
            mapping = new Mapping();
            InputSource is = new InputSource(new FileReader(map));
            is.setSystemId(mapFile);
            mapping.loadMapping(is);
            Unmarshaller unmarshaller = new Unmarshaller(mapping);
            RegistryFragment fragment = (RegistryFragment) unmarshaller.unmarshal(reader);
            assertNotNull(fragment);
            Vector securityEntries = fragment.getSecurityEntries();
            assertTrue("Security Entries exist", !securityEntries.isEmpty());

            // Test the wide-open entry
            boolean entryFound = false;
            Iterator securityIterator = null;
            for (securityIterator = securityEntries.iterator(); securityIterator.hasNext();)
            {
                SecurityEntry securityEntry = (SecurityEntry) securityIterator.next();
                if (securityEntry.getName().equals("wide_open") == true)
                {
                    entryFound = true;
                    SecurityReference securityReference = securityEntry.getSecurityRef();
                    assertNotNull("Security entry 'wide_open' has a SecurityReference", securityReference);
                    assertEquals("Got parent", "admin_only", securityReference.getParent());
                }
            }
            assertTrue("Found wide_open security entry", entryFound);

            // Test the use_only entry
            entryFound = false;
            for (securityIterator = securityEntries.iterator(); securityIterator.hasNext();)
            {
                SecurityEntry securityEntry = (SecurityEntry) securityIterator.next();
                if (securityEntry.getName().equals("user_only") == true)
                {
                    entryFound = true;
                    SecurityReference securityReference = securityEntry.getSecurityRef();
                    assertNull("Security entry 'user_open' has no SecurityReference", securityReference);
                }
            }
            assertEquals("Found user_only security entry", true, entryFound);
        }
    }

    /**
     * Tests IdentityElement unmarshaling entryset base stuff
     * @throws Exception
     */


    /*
      Configuration object to run Turbine outside a servlet container
      ( uses turbine.properties )
    */
    private static TurbineConfig config = null;

    /*
      Sets up TurbineConfig using the system property:
      <pre>turbine.properties</pre>
    */
    static
    {
        try
        {
           config = new TurbineConfig("../webapp", "/WEB-INF/conf/TurbineResources.properties");
           config.init();
        }
        catch (Exception e)
        {
            fail(StringUtils.stackTrace(e));
        }
    }


    public void testUnmarshallURL() throws Exception
    {
        System.out.println("Testing marshalling of Registry, URL");

        String xregFile = "../webapp/WEB-INF/psml/test/url-testcase.xreg";

        Mapping mapping = null;
        String mapFile = getMappingFileName();
        File map = new File(mapFile);
        if (map.exists() && map.isFile() && map.canRead())
        {
            try
            {
                FileReader reader = new FileReader(xregFile);
                mapping = new Mapping();
                InputSource is = new InputSource(new FileReader(map));
                is.setSystemId(mapFile);
                mapping.loadMapping(is);
                Unmarshaller unmarshaller = new Unmarshaller(mapping);
                ContentURL url = (ContentURL) unmarshaller.unmarshal(reader);
                assertNotNull(url);

                System.out.println(url.getURL());
                assertTrue(url.getURL().equals("http://www.xmlhack.com/rss.php"));
                assertTrue(url.isCacheKey());
            }
            catch (Exception e)
            {
                String errmsg = "Error in xreg mapping creation: " + e.toString();
                System.err.println(errmsg);
                assertNotNull(errmsg, null);
            }
        }
        else
        {
            String errmsg = "Registy Mapping not found or not a file or unreadable: ";
            System.err.println(errmsg);
            assertNotNull(errmsg, null);
        }

    }
}