org.apache.dubbo.rpc.model.ScopeModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dubbo Show documentation
Show all versions of dubbo Show documentation
The all in one project of dubbo
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.model;
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.common.config.Environment;
import org.apache.dubbo.common.extension.ExtensionAccessor;
import org.apache.dubbo.common.extension.ExtensionDirector;
import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.StringUtils;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNABLE_DESTROY_MODEL;
public abstract class ScopeModel implements ExtensionAccessor {
protected static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ScopeModel.class);
/**
* The internal id is used to represent the hierarchy of the model tree, such as:
*
* - 1
* FrameworkModel (index=1)
* - 1.2
* FrameworkModel (index=1) -> ApplicationModel (index=2)
* - 1.2.0
* FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=0, internal module)
* - 1.2.1
* FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=1, first user module)
*
*/
private String internalId;
/**
* Public Model Name, can be set from user
*/
private String modelName;
private String desc;
private Set classLoaders;
private final ScopeModel parent;
private final ExtensionScope scope;
private ExtensionDirector extensionDirector;
private ScopeBeanFactory beanFactory;
private List destroyListeners;
private List classLoaderListeners;
private Map attributes;
private final AtomicBoolean destroyed = new AtomicBoolean(false);
private final boolean internalScope;
public ScopeModel(ScopeModel parent, ExtensionScope scope, boolean isInternal) {
this.parent = parent;
this.scope = scope;
this.internalScope = isInternal;
}
/**
* NOTE:
*
* - The initialize method only be called in subclass.
* -
* In subclass, the extensionDirector and beanFactory are available in initialize but not available in constructor.
*
*
*/
protected void initialize() {
this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this);
this.extensionDirector.addExtensionPostProcessor(new ScopeModelAwareExtensionProcessor(this));
this.beanFactory = new ScopeBeanFactory(parent != null ? parent.getBeanFactory() : null, extensionDirector);
this.destroyListeners = new LinkedList<>();
this.classLoaderListeners = new LinkedList<>();
this.attributes = new ConcurrentHashMap<>();
this.classLoaders = new ConcurrentHashSet<>();
// Add Framework's ClassLoader by default
ClassLoader dubboClassLoader = ScopeModel.class.getClassLoader();
if (dubboClassLoader != null) {
this.addClassLoader(dubboClassLoader);
}
}
public void destroy() {
if (destroyed.compareAndSet(false, true)) {
try {
onDestroy();
HashSet copyOfClassLoaders = new HashSet<>(classLoaders);
for (ClassLoader classLoader : copyOfClassLoaders) {
removeClassLoader(classLoader);
}
if (beanFactory != null) {
beanFactory.destroy();
}
if (extensionDirector != null) {
extensionDirector.destroy();
}
} catch (Throwable t) {
LOGGER.error(CONFIG_UNABLE_DESTROY_MODEL, "", "", "Error happened when destroying ScopeModel.", t);
}
}
}
public boolean isDestroyed() {
return destroyed.get();
}
protected void notifyDestroy() {
for (ScopeModelDestroyListener destroyListener : destroyListeners) {
destroyListener.onDestroy(this);
}
}
protected void notifyProtocolDestroy() {
for (ScopeModelDestroyListener destroyListener : destroyListeners) {
if (destroyListener.isProtocol()) {
destroyListener.onDestroy(this);
}
}
}
protected void notifyClassLoaderAdd(ClassLoader classLoader) {
for (ScopeClassLoaderListener classLoaderListener : classLoaderListeners) {
classLoaderListener.onAddClassLoader(this, classLoader);
}
}
protected void notifyClassLoaderDestroy(ClassLoader classLoader) {
for (ScopeClassLoaderListener classLoaderListener : classLoaderListeners) {
classLoaderListener.onRemoveClassLoader(this, classLoader);
}
}
protected abstract void onDestroy();
public final void addDestroyListener(ScopeModelDestroyListener listener) {
destroyListeners.add(listener);
}
public final void addClassLoaderListener(ScopeClassLoaderListener listener) {
classLoaderListeners.add(listener);
}
public Map getAttributes() {
return attributes;
}
public T getAttribute(String key, Class type) {
return (T) attributes.get(key);
}
public Object getAttribute(String key) {
return attributes.get(key);
}
public void setAttribute(String key, Object value) {
attributes.put(key, value);
}
@Override
public ExtensionDirector getExtensionDirector() {
return extensionDirector;
}
public ScopeBeanFactory getBeanFactory() {
return beanFactory;
}
public ScopeModel getParent() {
return parent;
}
public ExtensionScope getScope() {
return scope;
}
public void addClassLoader(ClassLoader classLoader) {
this.classLoaders.add(classLoader);
if (parent != null) {
parent.addClassLoader(classLoader);
}
extensionDirector.removeAllCachedLoader();
notifyClassLoaderAdd(classLoader);
}
public void removeClassLoader(ClassLoader classLoader) {
if (checkIfClassLoaderCanRemoved(classLoader)) {
this.classLoaders.remove(classLoader);
if (parent != null) {
parent.removeClassLoader(classLoader);
}
extensionDirector.removeAllCachedLoader();
notifyClassLoaderDestroy(classLoader);
}
}
protected boolean checkIfClassLoaderCanRemoved(ClassLoader classLoader) {
return classLoader != null && !classLoader.equals(ScopeModel.class.getClassLoader());
}
public Set getClassLoaders() {
return Collections.unmodifiableSet(classLoaders);
}
public abstract Environment getModelEnvironment();
public String getInternalId() {
return this.internalId;
}
void setInternalId(String internalId) {
this.internalId = internalId;
}
protected String buildInternalId(String parentInternalId, long childIndex) {
// FrameworkModel 1
// ApplicationModel 1.1
// ModuleModel 1.1.1
if (StringUtils.hasText(parentInternalId)) {
return parentInternalId + "." + childIndex;
} else {
return "" + childIndex;
}
}
public String getModelName() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
this.desc = buildDesc();
}
public boolean isInternal() {
return internalScope;
}
/**
* @return to describe string of this scope model
*/
public String getDesc() {
if (this.desc == null) {
this.desc = buildDesc();
}
return this.desc;
}
private String buildDesc() {
// Dubbo Framework[1]
// Dubbo Application[1.1](appName)
// Dubbo Module[1.1.1](appName/moduleName)
String type = this.getClass().getSimpleName().replace("Model", "");
String desc = "Dubbo " + type + "[" + this.getInternalId() + "]";
// append model name path
String modelNamePath = this.getModelNamePath();
if (StringUtils.hasText(modelNamePath)) {
desc += "(" + modelNamePath + ")";
}
return desc;
}
private String getModelNamePath() {
if (this instanceof ApplicationModel) {
return safeGetAppName((ApplicationModel) this);
} else if (this instanceof ModuleModel) {
String modelName = this.getModelName();
if (StringUtils.hasText(modelName)) {
// appName/moduleName
return safeGetAppName(((ModuleModel) this).getApplicationModel()) + "/" + modelName;
}
}
return null;
}
private static String safeGetAppName(ApplicationModel applicationModel) {
String modelName = applicationModel.getModelName();
if (StringUtils.isBlank(modelName)) {
modelName = "unknown"; // unknown application
}
return modelName;
}
@Override
public String toString() {
return getDesc();
}
}