import static java.lang.String.format;
+import com.google.common.base.Preconditions;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
*/
final class DependencyResolverImpl implements DependencyResolver,
Comparable<DependencyResolverImpl> {
- private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class);
+ private static final Logger LOG = LoggerFactory.getLogger(DependencyResolverImpl.class);
private final ModulesHolder modulesHolder;
private final ModuleIdentifier name;
format("ObjectName should not contain "
+ "transaction name. %s set to %s. ", jmxAttribute,
dependentReadOnlyON
- ), jmxAttribute
+ ), jmxAttribute
);
- dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+ ObjectName newDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
- ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil
+ ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(newDependentReadOnlyON, ObjectNameUtil
.TYPE_MODULE);
ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
+ "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
+ "attribute %s",
foundFactory.getImplementationName(), foundFactory,
- expectedServiceInterface, dependentReadOnlyON,
+ expectedServiceInterface, newDependentReadOnlyON,
jmxAttribute
);
throw new JmxAttributeValidationException(message, jmxAttribute);
// translate from serviceref to module ON
private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
- if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
- String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
- String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON);
- dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name
+ ObjectName translatedDependentReadOnlyON = dependentReadOnlyON;
+ if (ObjectNameUtil.isServiceReference(translatedDependentReadOnlyON)) {
+ String serviceQName = ObjectNameUtil.getServiceQName(translatedDependentReadOnlyON);
+ String refName = ObjectNameUtil.getReferenceName(translatedDependentReadOnlyON);
+ translatedDependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name
readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName));
}
- return dependentReadOnlyON;
+ return translatedDependentReadOnlyON;
}
/**
@Override
public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
JmxAttribute jmxAttribute) {
- if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
- throw new IllegalArgumentException(format(
- "Null parameters not allowed, got %s %s %s", expectedType,
- dependentReadOnlyON, jmxAttribute));
- }
- dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
- transactionStatus.checkCommitStarted();
- transactionStatus.checkNotCommitted();
+ Module module = resolveModuleInstance(dependentReadOnlyON, jmxAttribute);
- ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
- dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
- Module module = modulesHolder.findModule(dependentModuleIdentifier,
- jmxAttribute);
synchronized (this) {
- dependencies.add(dependentModuleIdentifier);
+ dependencies.add(module.getIdentifier());
}
AutoCloseable instance = module.getInstance();
if (instance == null) {
String message = format(
"Error while %s resolving instance %s. getInstance() returned null. "
+ "Expected type %s , attribute %s", name,
- dependentModuleIdentifier, expectedType, jmxAttribute
+ module.getIdentifier(), expectedType, jmxAttribute
);
throw new JmxAttributeValidationException(message, jmxAttribute);
}
}
}
+ private Module resolveModuleInstance(ObjectName dependentReadOnlyON,
+ JmxAttribute jmxAttribute) {
+ Preconditions.checkArgument(dependentReadOnlyON != null ,"dependentReadOnlyON");
+ Preconditions.checkArgument(jmxAttribute != null, "jmxAttribute");
+ ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+ transactionStatus.checkCommitStarted();
+ transactionStatus.checkNotCommitted();
+
+ ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
+ translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
+
+ return Preconditions.checkNotNull(modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute));
+ }
+
+ @Override
+ public boolean canReuseDependency(ObjectName objectName, JmxAttribute jmxAttribute) {
+ Preconditions.checkNotNull(objectName);
+ Preconditions.checkNotNull(jmxAttribute);
+
+ Module currentModule = resolveModuleInstance(objectName, jmxAttribute);
+ ModuleIdentifier identifier = currentModule.getIdentifier();
+ ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = modulesHolder.findModuleInternalTransactionalInfo(identifier);
+
+ if(moduleInternalTransactionalInfo.hasOldModule()) {
+ Module oldModule = moduleInternalTransactionalInfo.getOldInternalInfo().getReadableModule().getModule();
+ return currentModule.canReuse(oldModule);
+ }
+ return false;
+ }
+
@Override
public <T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass) {
final QName qName = QName.create(identityRef.getqNameOfIdentity());
if (expectedBaseClass.isAssignableFrom(deserialized)) {
return (Class<T>) deserialized;
} else {
- logger.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.",
+ LOG.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.",
identityRef, deserialized, expectedBaseClass);
throw new IllegalArgumentException("Deserialized identity " + deserialized + " cannot be cast to " + expectedBaseClass);
}
@Override
public int compareTo(DependencyResolverImpl o) {
- transactionStatus.checkCommitted();
+ transactionStatus.checkCommitStarted();
return Integer.compare(getMaxDependencyDepth(),
o.getMaxDependencyDepth());
}
}
void countMaxDependencyDepth(DependencyResolverManager manager) {
- transactionStatus.checkCommitted();
+ // We can calculate the dependency after second phase commit was started
+ // Second phase commit starts after validation and validation adds the dependencies into the dependency resolver, which are necessary for the calculation
+ // FIXME generated code for abstract module declares validate method as non-final
+ // Overriding the validate would cause recreate every time instead of reuse + also possibly wrong close order if there is another module depending
+ transactionStatus.checkCommitStarted();
if (maxDependencyDepth == null) {
maxDependencyDepth = getMaxDepth(this, manager,
new LinkedHashSet<ModuleIdentifier>());
@Override
public Object getAttribute(ObjectName name, String attribute)
throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
- name = translateServiceRefIfPossible(name);
+ ObjectName newName = translateServiceRefIfPossible(name);
// add transaction name
- name = ObjectNameUtil.withTransactionName(name, transactionName);
- return mBeanServer.getAttribute(name, attribute);
+ newName = ObjectNameUtil.withTransactionName(newName, transactionName);
+ return mBeanServer.getAttribute(newName, attribute);
}
@Override
public <T> T newMXBeanProxy(ObjectName name, Class<T> interfaceClass) {
- name = translateServiceRefIfPossible(name);
+ ObjectName newName = translateServiceRefIfPossible(name);
// add transaction name
- name = ObjectNameUtil.withTransactionName(name, transactionName);
- return JMX.newMXBeanProxy(mBeanServer, name, interfaceClass);
+ newName = ObjectNameUtil.withTransactionName(newName, transactionName);
+ return JMX.newMXBeanProxy(mBeanServer, newName, interfaceClass);
}
}