Java tutorial
/******************************************************************************* * Copyright (c) 2008, 2009 Martin Lippert and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Martin Lippert initial implementation *******************************************************************************/ package org.eclipse.equinox.weaving.aspectj.loadtime; import java.net.URL; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.aspectj.weaver.loadtime.definition.Definition; import org.aspectj.weaver.loadtime.definition.DocumentParser; import org.aspectj.weaver.loadtime.definition.Definition.ConcreteAspect; import org.eclipse.equinox.weaving.aspectj.AspectAdmin; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; import org.osgi.framework.Constants; import org.osgi.framework.SynchronousBundleListener; /** * The AspectAdmin takes care of resolving aspect definitions of resolved * bundles and provides information which bundle should be woven with which * aspects. * * The AspectAdmin takes the aop.xml files into account as well as the aspect * definitions in the bundle manifests. * * All the information parsing and resolving is done at bundle resolve time, the * removal from the cache is done at unresolved events. The initial state is * re-created by the initialize method. * * @author Martin Lippert */ public class AspectAdminImpl implements AspectAdmin, SynchronousBundleListener { // remember all aspect definitions for the given bundle (regardless of the way they are declared) private final Map<Bundle, Definition> aspectDefinitions; // remember only the exported aspect definitions for the given bundle (regardless of the way they are declared) private final Map<Bundle, Definition> aspectDefinitionsExported; // remember the aspect policies per exported package per bundle private final Map<Bundle, Map<String, Integer>> aspectPolicies; /** * Create a registry to manage aspect definition files */ public AspectAdminImpl() { this.aspectDefinitions = new ConcurrentHashMap<Bundle, Definition>(); this.aspectDefinitionsExported = new ConcurrentHashMap<Bundle, Definition>(); this.aspectPolicies = new ConcurrentHashMap<Bundle, Map<String, Integer>>(); } /** * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent) */ public void bundleChanged(final BundleEvent event) { if (event.getType() == BundleEvent.RESOLVED) { bundleResolved(event.getBundle()); } else if (event.getType() == BundleEvent.UNRESOLVED) { bundleUnresolved(event.getBundle()); } } /** * Do the parsing when a bundle is resolved * * @param bundle The bundle that is resolved (should not be null) */ public void bundleResolved(final Bundle bundle) { if (!this.aspectDefinitions.containsKey(bundle) && !this.aspectDefinitionsExported.containsKey(bundle) && !this.aspectPolicies.containsKey(bundle)) { parseDefinitions(bundle); } } /** * Remove the cached aspect definitions from the aspect definition registry * * @param bundle The bundle that got unresolved (should not be null) */ public void bundleUnresolved(final Bundle bundle) { this.aspectDefinitions.remove(bundle); this.aspectDefinitionsExported.remove(bundle); this.aspectPolicies.remove(bundle); } /** * @see org.eclipse.equinox.weaving.aspectj.AspectAdmin#getAspectDefinition(org.osgi.framework.Bundle) */ public Definition getAspectDefinition(final Bundle bundle) { return this.aspectDefinitions.get(bundle); } /** * @see org.eclipse.equinox.weaving.aspectj.AspectAdmin#getAspectPolicy(org.osgi.framework.Bundle, * java.lang.String) */ public int getAspectPolicy(final Bundle bundle, final String packageName) { final Map<String, Integer> policies = this.aspectPolicies.get(bundle); if (policies != null) { final Integer policy = policies.get(packageName); if (policy != null) { return policy; } } return AspectAdmin.ASPECT_POLICY_NOT_DEFINED; } /** * Finds the location of the aspect definition within the given bundle. The * default location is "META-INF/aop.xml", but if the bundles manifest * contains an entry for "Eclipse-AspectContext", that value is used to * search for the aop.xml file. * * @param bundle The bundle for which to calculate the location of the * aspect definition file * @return The path to the aspect definition relately to the given bundle */ public String getDefinitionLocation(final Bundle bundle) { String aopContextHeader = bundle.getHeaders("").get( //$NON-NLS-1$ AOP_CONTEXT_LOCATION_HEADER); if (aopContextHeader != null) { aopContextHeader = aopContextHeader.trim(); return aopContextHeader; } return AOP_CONTEXT_DEFAULT_LOCATION; } /** * @see org.eclipse.equinox.weaving.aspectj.AspectAdmin#getExportedAspectDefinitions(org.osgi.framework.Bundle) */ public Definition getExportedAspectDefinitions(final Bundle bundle) { return this.aspectDefinitionsExported.get(bundle); } /** * Initialize the state of the aspect definition registry for the given * bundles. This should typically be called when the weaving service bundle * is started to set up the aspect definitions for all resolved bundles * * @param bundles All bundles that should be taken into account and searched * for aspect definitions * */ public void initialize(final Bundle[] bundles) { for (final Bundle bundle : bundles) { final int state = bundle.getState(); if (state != Bundle.INSTALLED && state != Bundle.UNINSTALLED) { parseDefinitions(bundle); } } } /** * @see org.eclipse.equinox.weaving.aspectj.AspectAdmin#resolveImportedPackage(org.osgi.framework.Bundle, * java.lang.String, int) */ public Definition resolveImportedPackage(final Bundle bundle, final String packageName, final int applyAspectsPolicy) { if (AspectAdmin.ASPECT_APPLY_POLICY_TRUE == applyAspectsPolicy) { final Definition exportedAspectDefinitions = getExportedAspectDefinitions(bundle); final Definition result = new Definition(); if (exportedAspectDefinitions != null) { final List<?> aspectClassNames = exportedAspectDefinitions.getAspectClassNames(); for (final Iterator<?> iterator = aspectClassNames.iterator(); iterator.hasNext();) { final String aspectName = (String) iterator.next(); final String aspectPackageName = getPackage(aspectName); if (aspectPackageName.equals(packageName)) { result.getAspectClassNames().add(aspectName); } } final Iterator<?> concreteAspects = exportedAspectDefinitions.getConcreteAspects().iterator(); while (concreteAspects.hasNext()) { final Definition.ConcreteAspect concreteAspect = (ConcreteAspect) concreteAspects.next(); if (concreteAspect.name != null && getPackage(concreteAspect.name).equals(packageName)) { result.getConcreteAspects().add(concreteAspect); } } if (exportedAspectDefinitions.getWeaverOptions().trim().length() > 0) { result.appendWeaverOptions(exportedAspectDefinitions.getWeaverOptions()); } } if (result.getAspectClassNames().size() > 0 || result.getConcreteAspects().size() > 0 || result.getWeaverOptions().length() > 0) { return result; } else { return null; } } else if (AspectAdmin.ASPECT_APPLY_POLICY_FALSE == applyAspectsPolicy) { return null; } else { final Definition exportedAspectDefinitions = getExportedAspectDefinitions(bundle); final Definition result = new Definition(); if (exportedAspectDefinitions != null) { final List<?> aspectClassNames = exportedAspectDefinitions.getAspectClassNames(); for (final Iterator<?> iterator = aspectClassNames.iterator(); iterator.hasNext();) { final String aspectName = (String) iterator.next(); final String aspectPackageName = getPackage(aspectName); final int aspectPolicy = getAspectPolicy(bundle, aspectPackageName); if (aspectPackageName.equals(packageName) && (AspectAdmin.ASPECT_POLICY_NOT_DEFINED == aspectPolicy || AspectAdmin.ASPECT_POLICY_OPT_OUT == aspectPolicy)) { result.getAspectClassNames().add(aspectName); } } final Iterator<?> concreteAspects = exportedAspectDefinitions.getConcreteAspects().iterator(); while (concreteAspects.hasNext()) { final Definition.ConcreteAspect concreteAspect = (ConcreteAspect) concreteAspects.next(); final String aspectPackageName = getPackage(concreteAspect.name); final int aspectPolicy = getAspectPolicy(bundle, aspectPackageName); if (aspectPackageName.equals(packageName) && (AspectAdmin.ASPECT_POLICY_NOT_DEFINED == aspectPolicy || AspectAdmin.ASPECT_POLICY_OPT_OUT == aspectPolicy)) { result.getConcreteAspects().add(concreteAspect); } } if (exportedAspectDefinitions.getWeaverOptions().trim().length() > 0) { result.appendWeaverOptions(exportedAspectDefinitions.getWeaverOptions()); } } if (result.getAspectClassNames().size() > 0 || result.getConcreteAspects().size() > 0 || result.getWeaverOptions().length() > 0) { return result; } else { return null; } } } /** * @see org.eclipse.equinox.weaving.aspectj.AspectAdmin#resolveRequiredBundle(org.osgi.framework.Bundle, * int) */ public Definition resolveRequiredBundle(final Bundle bundle, final int applyAspectsPolicy) { if (AspectAdmin.ASPECT_APPLY_POLICY_TRUE == applyAspectsPolicy) { return getExportedAspectDefinitions(bundle); } else if (AspectAdmin.ASPECT_APPLY_POLICY_FALSE == applyAspectsPolicy) { return null; } else { final Definition exportedAspectDefinitions = getExportedAspectDefinitions(bundle); final Definition result = new Definition(); if (exportedAspectDefinitions != null) { final Iterator<?> aspects = exportedAspectDefinitions.getAspectClassNames().iterator(); while (aspects.hasNext()) { final String aspect = (String) aspects.next(); final String aspectPackage = getPackage(aspect); final int aspectPolicy = getAspectPolicy(bundle, aspectPackage); if (aspectPolicy == AspectAdmin.ASPECT_POLICY_NOT_DEFINED || aspectPolicy == AspectAdmin.ASPECT_POLICY_OPT_OUT) { result.getAspectClassNames().add(aspect); } } final Iterator<?> concreteAspects = exportedAspectDefinitions.getConcreteAspects().iterator(); while (concreteAspects.hasNext()) { final Definition.ConcreteAspect concreteAspect = (Definition.ConcreteAspect) concreteAspects .next(); final String aspectPackage = getPackage(concreteAspect.name); final int aspectPolicy = getAspectPolicy(bundle, aspectPackage); if (aspectPolicy == AspectAdmin.ASPECT_POLICY_NOT_DEFINED || aspectPolicy == AspectAdmin.ASPECT_POLICY_OPT_OUT) { result.getConcreteAspects().add(concreteAspect); } } if (exportedAspectDefinitions.getWeaverOptions().trim().length() > 0) { result.appendWeaverOptions(exportedAspectDefinitions.getWeaverOptions()); } } if (result.getAspectClassNames().size() > 0 || result.getConcreteAspects().size() > 0 || result.getWeaverOptions().length() > 0) { return result; } else { return null; } } } /** * Parse the aspect definition for the given bundle, if there is one. * * @param bundle The bundle for which the aspect definition should be parsed */ protected void parseDefinitions(final Bundle bundle) { try { Definition allAspectsDefinition = null; final Set<String> exportedAspects = new LinkedHashSet<String>(); final Set<Definition.ConcreteAspect> exportedConcreteAspects = new HashSet<Definition.ConcreteAspect>(); final Map<String, Integer> policies = new HashMap<String, Integer>(); final Set<String> exportedPackages = new HashSet<String>(); // try to find aop.xml file final String aopXmlLocation = getDefinitionLocation(bundle); final URL aopXmlDef = bundle.getEntry(aopXmlLocation); if (aopXmlDef != null) { allAspectsDefinition = DocumentParser.parse(aopXmlDef); } // parse export package headers final Dictionary<?, ?> manifest = bundle.getHeaders(""); //$NON-NLS-1$ final ManifestElement[] exports = ManifestElement.parseHeader(Constants.EXPORT_PACKAGE, (String) manifest.get(Constants.EXPORT_PACKAGE)); for (int i = 0; exports != null && i < exports.length; i++) { final String packageName = exports[i].getValue(); exportedPackages.add(packageName); // policies final String policy = exports[i].getDirective(ASPECT_POLICY_DIRECTIVE); if (policy != null && policy.trim().toLowerCase().equals(ASPECT_POLICY_DIRECTIVE_OPT_OUT)) { policies.put(packageName, AspectAdmin.ASPECT_POLICY_OPT_OUT); } if (policy != null && policy.trim().toLowerCase().equals(ASPECT_POLICY_DIRECTIVE_OPT_IN)) { policies.put(packageName, AspectAdmin.ASPECT_POLICY_OPT_IN); } // aspects final String allaspects = exports[i].getAttribute(ASPECTS_ATTRIBUTE); if (allaspects != null) { final String[] aspects = ManifestElement.getArrayFromList(allaspects); if (aspects != null) { for (int j = 0; j < aspects.length; j++) { exportedAspects.add(packageName + "." + aspects[j]); //$NON-NLS-1$ } } } } // add aop.xml declared aspects to the list of exported aspects if their packages are exported if (allAspectsDefinition != null && allAspectsDefinition.getAspectClassNames() != null) { final Iterator<?> iterator = allAspectsDefinition.getAspectClassNames().iterator(); while (iterator.hasNext()) { final String aspect = (String) iterator.next(); final String packageName = getPackage(aspect); if (exportedPackages.contains(packageName)) { exportedAspects.add(aspect); } } } if (allAspectsDefinition != null && allAspectsDefinition.getConcreteAspects().size() > 0) { final Iterator<?> iterator = allAspectsDefinition.getConcreteAspects().iterator(); while (iterator.hasNext()) { final Definition.ConcreteAspect concreteAspect = (Definition.ConcreteAspect) iterator.next(); if (concreteAspect.name != null && exportedPackages.contains(getPackage(concreteAspect.name))) { exportedConcreteAspects.add(concreteAspect); } } } if (allAspectsDefinition != null) { this.aspectDefinitions.put(bundle, allAspectsDefinition); } if (exportedAspects.size() > 0 || exportedConcreteAspects.size() > 0 || (allAspectsDefinition != null && allAspectsDefinition.getWeaverOptions().length() > 0)) { final Definition exportedAspectsDefinition = new Definition(); exportedAspectsDefinition.getAspectClassNames().addAll(exportedAspects); exportedAspectsDefinition.getConcreteAspects().addAll(exportedConcreteAspects); if (allAspectsDefinition != null && allAspectsDefinition.getWeaverOptions().trim().length() > 0) { exportedAspectsDefinition.appendWeaverOptions(allAspectsDefinition.getWeaverOptions()); } this.aspectDefinitionsExported.put(bundle, exportedAspectsDefinition); } if (policies.size() > 0) { this.aspectPolicies.put(bundle, policies); } } catch (final Exception e) { e.printStackTrace(); } } private String getPackage(final String aspect) { final int index = aspect.lastIndexOf('.'); if (index >= 0) { return aspect.substring(0, index); } else { return ""; //$NON-NLS-1$ } } }