/* * Copyright 2010-2011 Research In Motion Limited. * * 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 net.rim.tumbler.file; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashSet; import java.util.Hashtable; import net.rim.tumbler.config.FeatureManager.ExtensionInfo; import net.rim.tumbler.exception.PackageException; import net.rim.tumbler.file.Library.Extension; import net.rim.tumbler.log.LogType; import net.rim.tumbler.log.Logger; /** * Logic for resolving dependencies for extensions */ public class ExtensionDependencyManager { private Hashtable<String, ExtensionInfo> _extensionLookupTable; private Deque<String> _inProgressStack; private HashSet<String> _resolvedDependencies; /** * Constructor * * @param extensionLookupTable * map with extension library info and paths indexed by extension * id, cannot be null */ public ExtensionDependencyManager( Hashtable<String, ExtensionInfo> extensionLookupTable) { _extensionLookupTable = extensionLookupTable; _inProgressStack = new ArrayDeque<String>(); _resolvedDependencies = new HashSet<String>(); } private void resolve(HashSet<String> extensions) throws Exception { for (String extId : extensions) { Library info = null; if (_extensionLookupTable.get(extId) != null) { info = _extensionLookupTable.get(extId).getLibrary(); } if (info != null) { _inProgressStack.push(extId); _resolvedDependencies.add(extId); ArrayList<Extension> dependencies = info.getDependencies(); if (dependencies != null && !dependencies.isEmpty()) { HashSet<String> deps = new HashSet<String>(); for (Extension e : dependencies) { if (!_inProgressStack.contains(e.getId())) { deps.add(e.getId()); } else { throw new PackageException("EXCEPTION_CIRCULAR_DEPENDENCY", e.getId()); } } resolve(deps); } _inProgressStack.pop(); } else { throw new PackageException("EXCEPTION_EXTENSION_NOT_FOUND", extId); } } } /** * Resolve dependencies recursively<br> * Base case: extension does not have any dependencies<br> * <br> * * Push an extension on the stack at the start of the resolve process. The * extension is popped off the stack when all its dependencies have been * resolved. * * @param extensions * @throws Exception * when a circular dependency is detected, or if an extension * listed as a dependency cannot be found in the lookup table */ public HashSet<String> resolveExtensions(HashSet<String> extensions) throws Exception { resolve(extensions); return _resolvedDependencies; } }