blob: dec7e331842023b1e18577cfc3295bff7fe083b7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 VMware Inc.
* 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:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.virgo.kernel.shim.scope.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.virgo.kernel.diagnostics.KernelLogEvents;
import org.eclipse.virgo.kernel.shim.scope.Scope;
import org.eclipse.virgo.kernel.shim.scope.ScopeFactory;
import org.eclipse.virgo.medic.eventlog.EventLogger;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
/**
* Creates {@link Scope} instances for {@link ServiceReference ServiceReferences} and for lookups.
* <p />
*
* <strong>Concurrent Semantics</strong><br />
*
* Threadsafe.
*
*/
public final class StandardScopeFactory implements ScopeFactory {
private static final String PROPERTY_BLUEPRINT_CONTEXT_SERVICE_NAME = "org.eclipse.gemini.blueprint.context.service.name";
private static final String PROPERTY_BEAN_NAME = "org.eclipse.gemini.blueprint.bean.name";
private final EventLogger eventLogger;
/*
* Share application scope properties between equivalent application scope instances
*/
private final Map<AppScope, ConcurrentHashMap<String, Object>> properties = new HashMap<AppScope, ConcurrentHashMap<String, Object>>();
public StandardScopeFactory(EventLogger eventLogger) {
this.eventLogger = eventLogger;
}
/**
* {@inheritDoc}
*/
public Scope getBundleScope(Bundle bundle) {
return isBundleScoped(bundle) ? createApplicationScope(bundle) : GlobalScope.INSTANCE;
}
/**
* @param bundle
* @return
*/
private Scope createApplicationScope(Bundle bundle) {
return getApplicationScope(getScopeName(bundle));
}
/**
* {@inheritDoc}
*/
public Scope getGlobalScope() {
return GlobalScope.INSTANCE;
}
/**
* {@inheritDoc}
*/
public Scope getServiceScope(ServiceReference ref) {
return Scope.SCOPE_ID_APP.equals(getScopeIdentifier(ref)) ? getBundleScope(ref.getBundle()) : getGlobalScope();
}
/**
* {@inheritDoc}
*/
public Scope getApplicationScope(String applicationScopeName) {
synchronized (this.properties) {
AppScope appScope = new AppScope(applicationScopeName);
ConcurrentHashMap<String, Object> props = this.properties.get(appScope);
if (props == null) {
props = new ConcurrentHashMap<String, Object>();
this.properties.put(appScope, props);
}
appScope.setProperties(props);
return appScope;
}
}
private String getScopeIdentifier(ServiceReference ref) {
String serviceScope = (String) ref.getProperty(Scope.PROPERTY_SERVICE_SCOPE);
if (serviceScope == null) {
/*
* Tolerate the former property name to avoid breaking dm Server 2.0.x users. Post 2.1.0 the former property
* name need not be supported. Issue a warning message to prompt users to change the name.
*/
serviceScope = (String) ref.getProperty("com.springsource.service.scope");
if (serviceScope == null) {
// Blueprint (application) contexts belong in the global scope.
if (ref.getProperty(PROPERTY_BLUEPRINT_CONTEXT_SERVICE_NAME) != null) {
serviceScope = Scope.SCOPE_ID_GLOBAL;
}
else
if (isBundleScoped(ref.getBundle())) {
serviceScope = Scope.SCOPE_ID_APP;
} else {
serviceScope = Scope.SCOPE_ID_GLOBAL;
}
} else {
this.eventLogger.log(KernelLogEvents.OLD_SCOPING_PROPERTY_USED, ref.getBundle().getSymbolicName(), ref.getBundle().getVersion(),
ref.getProperty(PROPERTY_BEAN_NAME));
}
}
return serviceScope;
}
private static boolean isBundleScoped(Bundle bundle) {
// TODO: reinstate return OsgiFrameworkUtils.getScopeName(bundle) != null;
return getScopeName(bundle) != null;
}
private static String getScopeName(Bundle bundle) {
// TODO: use OFUtils instead when in proper location
return (String) bundle.getHeaders().get("Module-Scope");
}
/**
* {@inheritDoc}
*/
public void destroyApplicationScope(Scope applicationScope) {
// TODO: reinstate Assert.isTrue(applicationScope instanceof AppScope, "wrong scope type");
AppScope appScope = (AppScope) applicationScope;
synchronized (this.properties) {
this.properties.remove(appScope);
}
}
private abstract static class StandardScope implements Scope {
private volatile ConcurrentHashMap<String, Object> properties;
protected StandardScope() {
}
final void setProperties(ConcurrentHashMap<String, Object> properties) {
// TODO: reinstate Assert.isNull(this.properties, "properties can only be set once");
this.properties = properties;
}
/**
* {@inheritDoc}
*/
public final Object getProperty(String propertyName) {
// TODO: reinstate Assert.isTrue(this.properties != null, "properties not set");
return this.properties.get(propertyName);
}
/**
* {@inheritDoc}
*/
public final void setProperty(String propertyName, Object propertyValue) {
// TODO: reinstate Assert.isTrue(this.properties != null, "properties not set");
this.properties.put(propertyName, propertyValue);
}
/**
* {@inheritDoc}
*/
public int hashCode() {
return 0;
}
/**
* {@inheritDoc}
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
StandardScope other = (StandardScope) obj;
/*
* Instances that have not had their properties set compare equal (unless overridden by subclasses).
* Instances that have had their properties set must use the same properties object reference to compare
* equal.
*/
if (properties == null || other.properties == null) {
return true;
} else if (properties != other.properties) {
return false;
}
return true;
}
}
private static class GlobalScope extends StandardScope {
static GlobalScope INSTANCE = new GlobalScope();
private GlobalScope() {
setProperties(new ConcurrentHashMap<String, Object>());
}
/**
* {@inheritDoc}
*/
public int hashCode() {
return 316;
}
public boolean equals(Object other) {
return other == this || other instanceof GlobalScope;
}
public String toString() {
return Scope.SCOPE_ID_GLOBAL;
}
public boolean isGlobal() {
return true;
}
public String getScopeName() {
// The global scope does not have a name.
return null;
}
}
private static class AppScope extends StandardScope {
private final String scopeName;
public AppScope(String scopeName) {
this.scopeName = scopeName;
}
/**
* {@inheritDoc}
*/
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((scopeName == null) ? 0 : scopeName.hashCode());
return result;
}
/**
* {@inheritDoc}
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AppScope other = (AppScope) obj;
if (scopeName == null) {
if (other.scopeName != null) {
return false;
}
} else if (!scopeName.equals(other.scopeName)) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
public String toString() {
return Scope.SCOPE_ID_APP + ":" + this.scopeName;
}
/**
* {@inheritDoc}
*/
public boolean isGlobal() {
return false;
}
public String getScopeName() {
return this.scopeName;
}
}
}