/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. * <p> */ package org.olat.core.extensions; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.olat.core.CoreSpringFactory; import org.olat.core.extensions.action.GenericActionExtension; import org.olat.core.logging.LogDelegator; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; /** * Description:<br> * Initial Date: 02.08.2005 <br> * @author Felix * @author guido */ public class ExtManager extends LogDelegator { private static ExtManager instance; private long timeOfExtensionStartup; private List<Extension> extensions; private Object lockObject = new Object(); private Map<Long,Extension> idExtensionlookup; private Map<ExtensionPointKeyPair,GenericActionExtension> navKeyGAExtensionlookup; /** * @return the instance */ public static ExtManager getInstance() { if (instance == null) { return instance = (ExtManager) CoreSpringFactory.getBean("extManager"); } return instance; } /** * [used by spring] */ public ExtManager() { // for spring framework and.. timeOfExtensionStartup = System.currentTimeMillis(); instance = this; } /** * @return the number of extensions */ public int getExtensionCnt() { return (getExtensions() == null? 0 : extensions.size()); } /** * @param i * @return the extension at pos i */ public Extension getExtension(int i) { return getExtensions().get(i); } /** * returns the corresponding extension for a given unique extension id. * if no Extension is found for the specified id, null is returned instead. * * @param id * @return the corresponding extension or null, if no extension is found for given id */ public Extension getExtensionByID(long id){ if(idExtensionlookup.containsKey(id)) return idExtensionlookup.get(id); else return null; } /** * returns the GenericActionExtension that corresponds to the given NavKey. if * no suiting GAE is found, null is returned. * * @param navKey * @return the GenericActionExtension or null */ public GenericActionExtension getActionExtensioByNavigationKey(String extensionPoint, String navKey) { ExtensionPointKeyPair key = new ExtensionPointKeyPair(extensionPoint, navKey); if (navKeyGAExtensionlookup.containsKey(key)) { return navKeyGAExtensionlookup.get(key); } return null; } /** * [used by spring] * @return list */ public List<Extension> getExtensions() { if (extensions == null) { synchronized(lockObject) { if (extensions == null) { extensions = initExtentions(); } } } return extensions; } /** * @return the time when the extmanager was initialized */ public long getTimeOfExtensionStartup() { return timeOfExtensionStartup; } private ArrayList<Extension> initExtentions() { logInfo("****** start loading extensions *********"); Map<Integer, Extension> orderKeys = new HashMap<Integer, Extension>(); idExtensionlookup = new HashMap<Long, Extension>(); navKeyGAExtensionlookup = new HashMap<ExtensionPointKeyPair, GenericActionExtension>(); ArrayList<Extension> extensionsList = new ArrayList<Extension>(); Map<String, Extension> extensionMap = CoreSpringFactory.getBeansOfType(Extension.class); Collection<Extension> extensionValues = extensionMap.values(); int count_disabled = 0; int count_duplid = 0; AtomicInteger count_duplnavkey = new AtomicInteger(0); boolean debug = isLogDebugEnabled(); // first build ordered list for (Extension extension : extensionValues) { if (!extension.isEnabled()) { count_disabled++; logInfo("* Disabled Extension got loaded :: " + extension + ". Check that you don't use it or that extension returns null for getExtensionFor() when disabled, resp. overwrite isEnabled().",null); } int orderKey = extension.getOrder(); if(orderKey == 0){ //not configured via spring (order not set) logDebug("Extension-Configuration Warning: Order-value was not set for extension=" + extension + ", set order-value to config positionioning of extension...",null); if(extension instanceof AbstractExtension){ ((AbstractExtension)extension).setOrder(100000); } } if (orderKeys.containsKey(orderKey)) { Extension occupant = orderKeys.get(orderKey); if(debug) logDebug("Extension-Configuration Problem: Dublicate order-value ("+extension.getOrder()+") for extension=" + extension + ", orderKey already occupied by "+occupant,null); } else { orderKeys.put(orderKey, extension); } Long uid = CodeHelper.getUniqueIDFromString(extension.getUniqueExtensionID()); if(idExtensionlookup.containsKey(uid)){ count_duplid++; logWarn("Devel-Info :: duplicate unique id generated for extensions :: "+uid+" [ ["+idExtensionlookup.get(uid)+"] and ["+extension+"] ]",null); }else{ extensionsList.add(extension); idExtensionlookup.put(uid, extension); if (extension instanceof GenericActionExtension) { GenericActionExtension gAE = (GenericActionExtension) extension; if (StringHelper.containsNonWhitespace(gAE.getNavigationKey()) && gAE.getExtensionPoints() != null) { List<String>extensionPoints = gAE.getExtensionPoints(); for(String extensionPoint:extensionPoints) { ExtensionPointKeyPair key = new ExtensionPointKeyPair(extensionPoint, gAE.getNavigationKey()); append(key, gAE, count_duplnavkey); List<String> alternativeNavigationKeys = gAE.getAlternativeNavigationKeys(); if(alternativeNavigationKeys != null && alternativeNavigationKeys.size() > 0) { for(String alternativeNavigationKey:alternativeNavigationKeys) { ExtensionPointKeyPair altKey = new ExtensionPointKeyPair(extensionPoint, alternativeNavigationKey); append(altKey, gAE, count_duplnavkey); } } } } } } if(debug) logDebug("Created unique-id "+uid+" for extension:: "+extension); } logInfo("Devel-Info :: initExtensions done. :: "+count_disabled+" disabled Extensions, "+count_duplid+" extensions with duplicate ids, "+count_duplnavkey+ " extensions with duplicate navigationKeys"); Collections.sort(extensionsList); return extensionsList; } private void append(ExtensionPointKeyPair key, GenericActionExtension gAE, AtomicInteger countDuplicate) { if (navKeyGAExtensionlookup.containsKey(key)) { logInfo("Devel-Info :: duplicate navigation-key for extension :: " + key.navigationKey, null); countDuplicate.incrementAndGet(); } else { navKeyGAExtensionlookup.put(key, gAE); } } private static class ExtensionPointKeyPair { private String extensionPoint; private String navigationKey; public ExtensionPointKeyPair(String extensionPoint, String navigationKey) { this.extensionPoint = extensionPoint; this.navigationKey = navigationKey; } @Override public int hashCode() { return (extensionPoint == null ? 9967811 : extensionPoint.hashCode()) + (navigationKey == null ? 8544 : navigationKey.hashCode()); } @Override public boolean equals(Object obj) { if(this == obj) { return true; } if(obj instanceof ExtensionPointKeyPair) { ExtensionPointKeyPair pair = (ExtensionPointKeyPair)obj; return extensionPoint != null && extensionPoint.equals(pair.extensionPoint) && navigationKey != null && navigationKey.equals(pair.navigationKey); } return false; } } }