Package org.socialmusicdiscovery.server.business.service.browse

Source Code of org.socialmusicdiscovery.server.business.service.browse.BrowseMenuManager

/*
*  Copyright 2010-2011, Social Music Discovery project
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions are met:
*      * Redistributions of source code must retain the above copyright
*        notice, this list of conditions and the following disclaimer.
*      * 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.
*      * Neither the name of Social Music Discovery project nor the
*        names of its contributors may be used to endorse or promote products
*        derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
*  ANY EXPRESS 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 SOCIAL MUSIC DISCOVERY PROJECT 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.
*/

package org.socialmusicdiscovery.server.business.service.browse;

import com.google.inject.Inject;
import com.google.inject.name.Named;
import nu.xom.*;
import org.socialmusicdiscovery.server.business.logic.InjectHelper;
import org.socialmusicdiscovery.server.business.logic.config.*;
import org.socialmusicdiscovery.server.business.model.config.ConfigurationParameter;
import org.socialmusicdiscovery.server.business.model.config.ConfigurationParameterEntity;
import org.socialmusicdiscovery.server.support.copy.CopyHelper;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
* The browse menu manager is responsible to manage all browse menus, both the default provided and those added by
* third party plugins. To handle this it loads menu configuration from default configuration, {@link org.socialmusicdiscovery.server.business.repository.config.ConfigurationParameterRepository}
* but also offers an API to add/remove menus.
*/
public class BrowseMenuManager {
    /**
     * Type of menu
     */
    public static enum MenuType {
        /**
         * Top level library menu
         */
        LIBRARY,
        /**
         * Context menu initiated from a selected object
         */
        CONTEXT
    }

    /**
     * Default value in-memory configuration manager
     */
    @Inject
    @Named("default-value")
    MemoryConfigurationManager defaultValueConfigurationManager;

    private Map<MenuType, List<MenuLevel>> menus = new HashMap<MenuType, List<MenuLevel>>();
    private Map<String, Class<? extends Command>> commands = new HashMap<String, Class<? extends Command>>();
    private Map<String, String> formats = new HashMap<String, String>();

    private ConfigurationManager configurationManager;

    public BrowseMenuManager() {
        InjectHelper.injectMembers(this);
        configurationManager = new MergedConfigurationManager(new PersistentConfigurationManager());
        this.menus.put(MenuType.CONTEXT,new ArrayList<MenuLevel>());
        this.menus.put(MenuType.LIBRARY,new ArrayList<MenuLevel>());
        try {
            loadMenusFromXml(getClass().getResourceAsStream("/org/socialmusicdiscovery/server/business/service/browse/menus.xml"));
            loadMenusFromXml(getClass().getResourceAsStream("/org/socialmusicdiscovery/server/business/service/browse/contextmenus.xml"));
        } catch (IOException e) {
            e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
        } catch (ParsingException e) {
            e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
        }
    }

    /**
     * Loads all menus from configuration from the specified menu configuration file
     *
     * @param inputStream input stream to load menu from
     */
    public void loadMenusFromXml(InputStream inputStream) throws IOException, ParsingException {
        Builder builder = new Builder();
        Document document = builder.build(inputStream);
        Element menusNode = document.getRootElement();
        if(menusNode!=null) {
            List<MenuLevel> menus = getMenusFromElement(null, menusNode);
            for (MenuLevel menu : menus) {
                if(menu.getContext()!=null) {
                    addMenu(MenuType.CONTEXT, menu);
                }else {
                    addMenu(MenuType.LIBRARY, menu);
                }
            }
        }
    }

    private List<MenuLevel> getMenusFromElement(MenuLevel parent, Element menusNode) {
        Elements menuNodes = menusNode.getChildElements("menu");
        List<MenuLevel> result = new ArrayList<MenuLevel>();
        for(int i=0;i<menuNodes.size();i++) {
            Element menu = menuNodes.get(i);
            MenuLevel level = getMenuFromElement(menu);
            Elements childMenus = menu.getChildElements("menus");
            if(childMenus.size()>0) {
                getMenusFromElement(level, childMenus.get(0));
            }
            if(parent!=null) {
                if(parent.getChildLevels()==null) {
                    parent.setChildLevels(new ArrayList<MenuLevel>());
                }
                parent.getChildLevels().add(level);
            }else {
                Nodes contexts = menu.query("contexts/context");
                if(contexts.size()>0) {
                    for(int j=0;j<contexts.size();j++) {
                        MenuLevel copy = new CopyHelper().copy(level);
                        copy.setContext((contexts.get(j)).getValue());
                        result.add(copy);
                    }
                }else {
                    result.add(level);
                }
            }
        }
        return result;
    }

    private String getMenuName(Elements labelsNode) {
        if (labelsNode == null || labelsNode.size() == 0) {
            return null;
        }

        Nodes labelNodes = labelsNode.get(0).query("label[@language='EN']");
        if (labelNodes.size() > 0) {
            return labelNodes.get(0).getValue();
        }
        return null;
    }

    private MenuLevel getMenuFromElement(Element menuNode) {
        String type = menuNode.getAttributeValue("type");
        AbstractMenuLevel level;
        if(MenuLevelCommand.TYPE.equals(type)) {
            String id = menuNode.getAttributeValue("id");
            level = new MenuLevelCommand(id,getMenuName(menuNode.getChildElements("labels")));

            List<String> parameters = null;
            Nodes parametersNode = menuNode.query("parameters/parameter");
            for(int i=0;i<parametersNode.size();i++) {
                Node parameter = parametersNode.get(i);
                if(parameters == null) {
                    parameters = new ArrayList<String>();
                }
                parameters.add(parameter.getValue());
            }
            ((MenuLevelCommand)level).setParameters(parameters);
        }else if(MenuLevelFolder.TYPE.equals(type)) {
            String id = menuNode.getAttributeValue("id");
            level = new MenuLevelFolder(id,getMenuName(menuNode.getChildElements("labels")), (List<MenuLevel>)null);
        }else if(MenuLevelImageFolder.TYPE.equals(type)) {
            String id = menuNode.getAttributeValue("id");
            level = new MenuLevelImageFolder(id,getMenuName(menuNode.getChildElements("labels")), (List<MenuLevel>)null);
        }else {
            String format = null;
            if(menuNode.getAttributeValue("format")!=null) {
                format = menuNode.getAttributeValue("format");
            }
            String playable = "true";
            if(menuNode.getAttributeValue("playable")!=null) {
                playable = menuNode.getAttributeValue("playable");
            }
            Long criteriaDepth = null;
            if(menuNode.getAttributeValue("criteriaDepth")!=null) {
                criteriaDepth = Long.valueOf(menuNode.getAttributeValue("criteriaDepth"));
            }
            level = new MenuLevelDynamic(type, getMenuName(menuNode.getChildElements("labels")), format, Boolean.valueOf(playable), criteriaDepth);
        }

        Nodes includedClientTypeNodes = menuNode.query("visibleOn/clientType");
        if(includedClientTypeNodes.size()>0) {
            for(int j=0;j<includedClientTypeNodes.size();j++) {
                level.getIncludedClientTypes().add(includedClientTypeNodes.get(j).getValue());
            }
        }

        Nodes excludedClientTypeNodes = menuNode.query("hiddenOn/clientType");
        if(excludedClientTypeNodes.size()>0) {
            for(int j=0;j<excludedClientTypeNodes.size();j++) {
                level.getExcludedClientTypes().add(excludedClientTypeNodes.get(j).getValue());
            }
        }

        if(menuNode.getAttributeValue("weight")!=null) {
            level.setWeight(Integer.valueOf(menuNode.getAttributeValue("weight")));
        }
        return level;
    }

    /**
     * Add new default item format, this will be used of now specific format has been configured on a specific menu item
     *
     * @param menuType   Type of menu
     * @param objectType Type of item
     * @param format     The format to use, see {@link org.socialmusicdiscovery.server.support.format.TitleFormat} for more information
     */
    public void addDefaultItemFormat(MenuType menuType, String objectType, String format) {
        defaultValueConfigurationManager.setParameter(new ConfigurationParameterEntity(getClass().getName() + "." + menuType + ".formats."+objectType, ConfigurationParameter.Type.STRING,format));
    }

    /**
     * Remove a previously existed default item format
     *
     * @param menuType   Type of menu
     * @param objectType Type of item
     */
    public void removeDefaultItemFormat(MenuType menuType, String objectType) {
        formats.remove(menuType + "." + objectType);
    }

    /**
     * Get the default item format for the specified object type
     *
     * @param menuType   Menu type to get format for
     * @param objectType Object type to get format for
     * @return The default item format for the object type or null if no default format exist
     */
    public String getDefaultItemFormat(MenuType menuType, String objectType) {
        if (!this.formats.containsKey(menuType + "." + objectType)) {
            MappedConfigurationContext formatConfigs = new MappedConfigurationContext(getClass().getName() + "." + menuType + ".formats.", configurationManager);

            String format = formatConfigs.getStringParameter(objectType);
            if (format == null && objectType.contains(".")) {
                format = formatConfigs.getStringParameter(objectType.substring(0, objectType.indexOf(".")));
            }
            if (format != null) {
                this.formats.put(menuType + "." + objectType, format);
            }
        }
        return this.formats.get(menuType + "." + objectType);
    }

    private void addDefaultFormat(MenuType menuType, MenuLevel level) {
        if (level instanceof MenuLevelDynamic && ((MenuLevelDynamic)level).getFormat() == null) {
            ((MenuLevelDynamic)level).setFormat(getDefaultItemFormat(menuType, level.getType()));
        }
        if(level.getChildLevels()!=null) {
            for (MenuLevel childLevel : level.getChildLevels()) {
                addDefaultFormat(menuType, childLevel);
            }
        }
    }
    /**
     * Add a new menu for the specified menu type
     *
     * @param menuType Menu type to add menu in
     * @param menu     Menu to add
     */
    public void addMenu(MenuType menuType, MenuLevel menu) {
        addDefaultFormat(menuType, menu);
        if(this.menus.get(menuType)!=null) {
            addToHierarchy(this.menus.get(menuType), Arrays.asList(menu));
        }else {
            this.menus.put(menuType, Arrays.asList(menu));
        }
    }

    private void addToHierarchy(List<MenuLevel> existingLevels, List<MenuLevel> newLevels) {
        for (MenuLevel newLevel : newLevels) {
            MenuLevel matchingLevel = null;
            for (MenuLevel existingLevel : existingLevels) {
                if(newLevel.getId().equals(existingLevel.getId()) &&
                        ((newLevel.getContext()==null && existingLevel.getContext()==null) ||
                         (newLevel.getContext()!=null && newLevel.getContext().equals(existingLevel.getContext())))) {

                    matchingLevel = existingLevel;
                    break;
                }
            }
            if(matchingLevel==null) {
                existingLevels.add(newLevel);
                sortMenuLevels(existingLevels);
            }else {
                if(matchingLevel.getChildLevels()==null && newLevel.getChildLevels()!=null) {
                    matchingLevel.setChildLevels(new ArrayList<MenuLevel>());
                }
                if(newLevel.getChildLevels()!=null) {
                    addToHierarchy(matchingLevel.getChildLevels(), newLevel.getChildLevels());
                }
            }
        }
    }

    /**
     * Remove a previously added menu
     *
     * @param menuType The menu type the menu was registered for
     * @param id       The id of the menu, see {@link org.socialmusicdiscovery.server.business.service.browse.MenuLevel#getId()}
     */
    public void removeMenu(MenuType menuType, String id) {
        this.menus.get(menuType).remove(id);
    }

    /**
     * Remove a previously added menu
     *
     * @param menuType The menu type the menu was registered for
     * @param context  The context the menu was registered in, see {@link org.socialmusicdiscovery.server.business.service.browse.MenuLevel#getContext()}
     * @param id       The id of the menu, see {@link org.socialmusicdiscovery.server.business.service.browse.MenuLevel#getId()}
     */
    public void removeMenu(MenuType menuType, String context, String id) {
        this.menus.get(menuType).remove(context + "." + id);
    }

    /**
     * Get all menus for the specified menu type
     *
     * @param menuType The typ of menus to get
     * @return A sorted list of menus which are available for the specified item type
     */
    public List<MenuLevel> getAllMenus(MenuType menuType) {
        return getAllMenus(menuType, null);
    }

    /**
     * Get all menus for the specified menu type
     *
     * @param menuType The typ of menus to get
     * @param context The context which the menu items has to be related to
     * @return A sorted list of menus which are available for the specified item type
     */
    public List<MenuLevel> getAllMenus(MenuType menuType, String context) {
        List<MenuLevel> result = new ArrayList<MenuLevel>(this.menus.get(menuType).size());

        String baseContext = context;
        if (context != null && context.contains(".")) {
            baseContext = context.substring(0, context.indexOf("."));
        }
        for (MenuLevel level : this.menus.get(menuType)) {
            if((context==null && level.getContext()==null) ||
              (level.getContext()!=null &&
                      (level.getContext().equals(context) || level.getContext().equals(baseContext)))) {

                result.add(level);
            }
        }
        sortMenuLevels(result);
        return result;
    }

    private void sortMenuLevels(List<MenuLevel> levels) {
        Collections.sort(levels, new Comparator<MenuLevel>() {
            @Override
            public int compare(MenuLevel m1, MenuLevel m2) {
                int weight = m1.getWeight().compareTo(m2.getWeight());
                if (weight == 0) {
                    return m1.getDisplayName().compareTo(m2.getDisplayName());
                } else {
                    return weight;
                }
            }
        });
    }
    public void addCommand(String commandId, Class<? extends Command> browseCommandService) {
        this.commands.put(commandId, browseCommandService);

    }

    public void removeCommand(String commandId) {
        this.commands.remove(commandId);
    }

    public Command getCommand(String commandId) {
        try {
            return this.commands.get(commandId).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
}
TOP

Related Classes of org.socialmusicdiscovery.server.business.service.browse.BrowseMenuManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.