/*
* 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 org.apache.aries.subsystem.core.internal;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.aries.subsystem.AriesSubsystem;
import org.apache.aries.subsystem.core.archive.AriesProvisionDependenciesDirective;
import org.apache.aries.subsystem.core.archive.AriesSubsystemParentsHeader;
import org.apache.aries.subsystem.core.archive.DeployedContentHeader;
import org.apache.aries.subsystem.core.archive.DeploymentManifest;
import org.apache.aries.subsystem.core.archive.Header;
import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader;
import org.apache.aries.subsystem.core.archive.SubsystemContentHeader;
import org.apache.aries.subsystem.core.archive.SubsystemManifest;
import org.apache.aries.subsystem.core.archive.SubsystemTypeHeader;
import org.apache.aries.util.filesystem.FileSystem;
import org.apache.aries.util.filesystem.ICloseableDirectory;
import org.apache.aries.util.filesystem.IDirectory;
import org.apache.aries.util.io.IOUtils;
import org.eclipse.equinox.region.Region;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import org.osgi.service.coordinator.Coordination;
import org.osgi.service.coordinator.Participant;
import org.osgi.service.resolver.ResolutionException;
import org.osgi.service.subsystem.Subsystem;
import org.osgi.service.subsystem.SubsystemConstants;
import org.osgi.service.subsystem.SubsystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BasicSubsystem implements Resource, AriesSubsystem {
private static final Logger logger = LoggerFactory.getLogger(BasicSubsystem.class);
public static final String ROOT_SYMBOLIC_NAME = "org.osgi.service.subsystem.root";
public static final Version ROOT_VERSION = Version.parseVersion("1.0.0");
public static final String ROOT_LOCATION = "subsystem://?"
+ SubsystemConstants.SUBSYSTEM_SYMBOLICNAME + '='
+ ROOT_SYMBOLIC_NAME + '&' + SubsystemConstants.SUBSYSTEM_VERSION
+ '=' + ROOT_VERSION;
private volatile Bundle regionContextBundle;
private DeploymentManifest deploymentManifest;
private SubsystemResource resource;
private SubsystemManifest subsystemManifest;
private final IDirectory directory;
public BasicSubsystem(SubsystemResource resource) throws URISyntaxException, IOException, BundleException, InvalidSyntaxException {
this(resource, null);
}
public BasicSubsystem(SubsystemResource resource, InputStream deploymentManifest) throws URISyntaxException, IOException, BundleException, InvalidSyntaxException {
this.resource = resource;
final File file = new File(Activator.getInstance().getBundleContext().getDataFile(""), Long.toString(resource.getId()));
file.mkdirs();
Coordination coordination = Activator.getInstance().getCoordinator().peek();
if (coordination != null) {
coordination.addParticipant(new Participant() {
@Override
public void ended(Coordination c) throws Exception {
// Nothing
}
@Override
public void failed(Coordination c) throws Exception {
IOUtils.deleteRecursive(file);
}
});
}
directory = FileSystem.getFSRoot(file);
setSubsystemManifest(resource.getSubsystemManifest());
SubsystemManifestValidator.validate(this, getSubsystemManifest());
setDeploymentManifest(new DeploymentManifest.Builder()
.manifest(resource.getSubsystemManifest())
.manifest(deploymentManifest == null ? resource.getDeploymentManifest() : new DeploymentManifest(deploymentManifest))
.location(resource.getLocation())
.autostart(false)
.id(resource.getId())
.lastId(SubsystemIdentifier.getLastId())
.region(resource.getRegion().getName())
.state(State.INSTALLING)
.build());
setTranslations();
}
public BasicSubsystem(File file) throws IOException, URISyntaxException, ResolutionException {
this(FileSystem.getFSRoot(file));
}
public BasicSubsystem(IDirectory directory) throws IOException,
URISyntaxException, ResolutionException {
this.directory = directory;
State state = State
.valueOf(getDeploymentManifestHeaderValue(DeploymentManifest.ARIESSUBSYSTEM_STATE));
if (EnumSet.of(State.STARTING, State.ACTIVE, State.STOPPING).contains(
state)) {
state = State.RESOLVED;
}
else if (State.RESOLVING.equals(state)) {
state = State.INSTALLED;
}
setDeploymentManifest(new DeploymentManifest.Builder()
.manifest(getDeploymentManifest()).state(state).build());
}
/* BEGIN Resource interface methods. */
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof BasicSubsystem))
return false;
BasicSubsystem that = (BasicSubsystem)o;
return getLocation().equals(that.getLocation());
}
@Override
public List<Capability> getCapabilities(String namespace) {
// First, add the capabilities from the manifest.
SubsystemManifest manifest = getSubsystemManifest();
List<Capability> result = manifest.toCapabilities(this);
if (namespace != null)
for (Iterator<Capability> i = result.iterator(); i.hasNext();)
if (!i.next().getNamespace().equals(namespace))
i.remove();
// TODO Somehow, exposing the capabilities of content resources of a
// feature is causing an infinite regression of feature2 installations
// in FeatureTest.testSharedContent() under certain conditions.
if (isScoped() || IdentityNamespace.IDENTITY_NAMESPACE.equals(namespace))
return result;
SubsystemContentHeader header = manifest.getSubsystemContentHeader();
for (Resource constituent : getConstituents()) {
if (header.contains(constituent)) {
for (Capability capability : constituent.getCapabilities(namespace)) {
if (namespace == null && (IdentityNamespace.IDENTITY_NAMESPACE.equals(capability.getNamespace()) || HostNamespace.HOST_NAMESPACE.equals(capability.getNamespace()))) {
// Don't want to include the osgi.identity and/or osgi.wiring.host capabilities of
// content. Need a second check here in case the namespace
// is null.
continue;
}
result.add(new BasicCapability(capability, this));
}
}
}
return result;
}
@Override
public List<Requirement> getRequirements(String namespace) {
// First, add the requirements from the manifest.
SubsystemManifest manifest = getSubsystemManifest();
List<Requirement> result = manifest.toRequirements(this);
if (namespace != null)
for (Iterator<Requirement> i = result.iterator(); i.hasNext();)
if (!i.next().getNamespace().equals(namespace))
i.remove();
if (isScoped())
return result;
SubsystemContentHeader header = manifest.getSubsystemContentHeader();
for (Resource constituent : getConstituents())
if (header.contains(constituent))
for (Requirement requirement : constituent.getRequirements(namespace))
result.add(new BasicRequirement(requirement, this));
return result;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + getLocation().hashCode();
return result;
}
/* END Resource interface methods. */
/* BEGIN Subsystem interface methods. */
@Override
public BundleContext getBundleContext() {
SecurityManager.checkContextPermission(this);
return AccessController.doPrivileged(new GetBundleContextAction(this));
}
@Override
public Collection<Subsystem> getChildren() {
return Activator.getInstance().getSubsystems().getChildren(this);
}
@Override
public Map<String, String> getSubsystemHeaders(Locale locale) {
SecurityManager.checkMetadataPermission(this);
return AccessController.doPrivileged(new GetSubsystemHeadersAction(this, locale));
}
@Override
public String getLocation() {
SecurityManager.checkMetadataPermission(this);
return getDeploymentManifestHeaderValue(DeploymentManifest.ARIESSUBSYSTEM_LOCATION);
}
@Override
public Collection<Subsystem> getParents() {
AriesSubsystemParentsHeader header = getDeploymentManifest().getAriesSubsystemParentsHeader();
if (header == null)
return Collections.emptyList();
Collection<Subsystem> result = new ArrayList<Subsystem>(header.getClauses().size());
for (AriesSubsystemParentsHeader.Clause clause : header.getClauses()) {
BasicSubsystem subsystem = Activator.getInstance().getSubsystems().getSubsystemById(clause.getId());
if (subsystem == null)
continue;
result.add(subsystem);
}
return result;
}
@Override
public Collection<Resource> getConstituents() {
return Activator.getInstance().getSubsystems().getConstituents(this);
}
@Override
public State getState() {
return State.valueOf(getDeploymentManifestHeaderValue(DeploymentManifest.ARIESSUBSYSTEM_STATE));
}
@Override
public long getSubsystemId() {
return Long.parseLong(getDeploymentManifestHeaderValue(DeploymentManifest.ARIESSUBSYSTEM_ID));
}
@Override
public String getSymbolicName() {
return getSubsystemManifest().getSubsystemSymbolicNameHeader().getSymbolicName();
}
@Override
public String getType() {
return getSubsystemManifest().getSubsystemTypeHeader().getType();
}
@Override
public Version getVersion() {
return getSubsystemManifest().getSubsystemVersionHeader().getVersion();
}
/** Get "aries-provision-dependencies" directive.
*
* @return requested directive or null if the directive is not specified in the header
*/
public AriesProvisionDependenciesDirective getAriesProvisionDependenciesDirective() {
return getSubsystemManifest().getSubsystemTypeHeader().getAriesProvisionDependenciesDirective();
}
@Override
public AriesSubsystem install(String location) {
return install(location, (InputStream)null);
}
@Override
public AriesSubsystem install(String location, InputStream content) {
return install(location, content, null);
}
@Override
public void start() {
SecurityManager.checkExecutePermission(this);
// Changing the autostart setting must be privileged because of file IO.
// It cannot be done within StartAction because we only want to change
// it on an explicit start operation but StartAction is also used for
// implicit operations.
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
setAutostart(true);
return null;
}
});
AccessController.doPrivileged(new StartAction(this, this, this));
}
@Override
public void stop() {
SecurityManager.checkExecutePermission(this);
// Changing the autostart setting must be privileged because of file IO.
// It cannot be done within StopAction because we only want to change it
// on an explicit stop operation but StopAction is also used for
// implicit operations.
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
setAutostart(false);
return null;
}
});
AccessController.doPrivileged(new StopAction(this, this, !isRoot()));
}
@Override
public void uninstall() {
SecurityManager.checkLifecyclePermission(this);
AccessController.doPrivileged(new UninstallAction(this, this, false));
}
/* END Subsystem interface methods. */
void addedConstituent(Resource resource, boolean referenced) {
try {
if (logger.isDebugEnabled())
logger.debug("Adding constituent {} to deployment manifest...", resource);
synchronized (this) {
setDeploymentManifest(new DeploymentManifest.Builder()
.manifest(getDeploymentManifest()).content(resource, referenced).build());
}
if (logger.isDebugEnabled())
logger.debug("Added constituent {} to deployment manifest", resource);
} catch (Exception e) {
throw new SubsystemException(e);
}
}
void addedParent(BasicSubsystem subsystem, boolean referenceCount) {
try {
if (logger.isDebugEnabled())
logger.debug("Adding parent {} to deployment manifest...", subsystem.getSymbolicName());
synchronized (this) {
setDeploymentManifest(new DeploymentManifest.Builder()
.manifest(getDeploymentManifest()).parent(subsystem, referenceCount).build());
}
if (logger.isDebugEnabled())
logger.debug("Added parent {} to deployment manifest", subsystem.getSymbolicName());
} catch (Exception e) {
throw new SubsystemException(e);
}
}
synchronized DeploymentManifest getDeploymentManifest() {
if (deploymentManifest == null) {
try {
deploymentManifest = new DeploymentManifest(directory.getFile("OSGI-INF/DEPLOYMENT.MF").open());
}
catch (Throwable t) {
throw new SubsystemException(t);
}
}
return deploymentManifest;
}
File getDirectory() {
try {
return new File(directory.toURL().toURI());
}
catch (Exception e) {
throw new SubsystemException(e);
}
}
Region getRegion() {
Bundle bundle = regionContextBundle; // volatile variable
if (bundle == null) {
// At best, RegionDigraph.getRegion(String) is linear time.
// Continue to call this when necessary, however, as a fail safe.
return Activator.getInstance().getRegionDigraph().getRegion(getRegionName());
}
// RegionDigraph.getRegion(Bundle) is constant time.
return Activator.getInstance().getRegionDigraph().getRegion(bundle);
}
String getRegionName() {
DeploymentManifest manifest = getDeploymentManifest();
Header<?> header = manifest.getHeaders().get(DeploymentManifest.ARIESSUBSYSTEM_REGION);
if (header == null)
return null;
return header.getValue();
}
synchronized SubsystemResource getResource() {
if (resource == null) {
try {
resource = new SubsystemResource(null, directory);
}
catch (Exception e) {
throw new SubsystemException(e);
}
Collection<DeployedContentHeader.Clause> missingResources = resource.getMissingResources();
if (!missingResources.isEmpty()) {
if (isRoot())
// We don't care if the root subsystem has missing resources
// because they are either (1) extraneous bundles outside of
// the subsystems API or (2) provisioned dependencies of
// other subsystems. Those that fall in the latter category
// will be detected by the dependent subsystems.
removedContent(missingResources);
else
// If a non-root subsystem has missing dependencies, let's
// fail fast for now.
throw new SubsystemException("Missing resources: " + missingResources);
}
}
return resource;
}
synchronized SubsystemManifest getSubsystemManifest() {
if (subsystemManifest == null) {
try {
subsystemManifest = new SubsystemManifest(directory.getFile("OSGI-INF/SUBSYSTEM.MF").open());
}
catch (Throwable t) {
throw new SubsystemException(t);
}
}
return subsystemManifest;
}
boolean isApplication() {
return getSubsystemManifest().getSubsystemTypeHeader().isApplication();
}
boolean isAutostart() {
DeploymentManifest manifest = getDeploymentManifest();
Header<?> header = manifest.getHeaders().get(DeploymentManifest.ARIESSUBSYSTEM_AUTOSTART);
return Boolean.valueOf(header.getValue());
}
boolean isComposite() {
return getSubsystemManifest().getSubsystemTypeHeader().isComposite();
}
boolean isFeature() {
return getSubsystemManifest().getSubsystemTypeHeader().isFeature();
}
boolean isReadyToStart() {
if (isRoot())
return true;
for (Subsystem parent : getParents())
if (EnumSet.of(State.STARTING, State.ACTIVE).contains(parent.getState()) && isAutostart())
return true;
return false;
}
boolean isReferenced(Resource resource) {
// Everything is referenced for the root subsystem during initialization.
if (isRoot() && EnumSet.of(State.INSTALLING, State.INSTALLED).contains(getState()))
return true;
DeployedContentHeader header = getDeploymentManifest().getDeployedContentHeader();
if (header == null)
return false;
return header.isReferenced(resource);
}
boolean isRoot() {
return ROOT_LOCATION.equals(getLocation());
}
boolean isScoped() {
return isApplication() || isComposite();
}
void removedContent(Resource resource) {
DeploymentManifest manifest = getDeploymentManifest();
DeployedContentHeader header = manifest.getDeployedContentHeader();
if (header == null)
return;
DeployedContentHeader.Clause clause = header.getClause(resource);
if (clause == null)
return;
removedContent(Collections.singleton(clause));
}
synchronized void removedContent(Collection<DeployedContentHeader.Clause> content) {
DeploymentManifest manifest = getDeploymentManifest();
DeployedContentHeader header = manifest.getDeployedContentHeader();
if (header == null)
return;
Collection<DeployedContentHeader.Clause> clauses = new ArrayList<DeployedContentHeader.Clause>(header.getClauses());
for (Iterator<DeployedContentHeader.Clause> i = clauses.iterator(); i.hasNext();)
if (content.contains(i.next())) {
i.remove();
break;
}
DeploymentManifest.Builder builder = new DeploymentManifest.Builder();
for (Entry<String, Header<?>> entry : manifest.getHeaders().entrySet()) {
if (DeployedContentHeader.NAME.equals(entry.getKey()))
continue;
builder.header(entry.getValue());
}
if (!clauses.isEmpty())
builder.header(new DeployedContentHeader(clauses));
try {
setDeploymentManifest(builder.build());
} catch (Exception e) {
throw new SubsystemException(e);
}
}
void setAutostart(boolean value) {
try {
synchronized (this) {
setDeploymentManifest(new DeploymentManifest.Builder()
.manifest(getDeploymentManifest()).autostart(value).build());
}
} catch (Exception e) {
throw new SubsystemException(e);
}
}
synchronized void setDeploymentManifest(DeploymentManifest value) throws IOException {
deploymentManifest = value;
Coordination coordination = Activator.getInstance().getCoordinator().peek();
if (logger.isDebugEnabled())
logger.debug("Setting deployment manifest for subsystem {} using coordination {}", getSymbolicName(), coordination == null ? null : coordination.getName());
if (coordination == null) {
saveDeploymentManifest();
} else {
Map<Class<?>, Object> variables = coordination.getVariables();
synchronized (variables) {
@SuppressWarnings("unchecked")
Set<BasicSubsystem> dirtySubsystems = (Set<BasicSubsystem>) variables.get(SaveManifestParticipant.class);
if (dirtySubsystems == null) {
// currently no dirty subsystems found;
// create a list to hold them and store it as a variable
dirtySubsystems = new HashSet<BasicSubsystem>();
variables.put(SaveManifestParticipant.class, dirtySubsystems);
// add the save manifest participant
coordination.addParticipant(new SaveManifestParticipant());
}
dirtySubsystems.add(this);
}
}
}
synchronized void saveDeploymentManifest() throws IOException {
File file = new File(getDirectory(), "OSGI-INF");
if (!file.exists())
file.mkdirs();
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(file, "DEPLOYMENT.MF")));
try {
if (logger.isDebugEnabled())
logger.debug("Writing deployment manifest for subsystem {} in state {}", getSymbolicName(), getState());
deploymentManifest.write(out);
if (logger.isDebugEnabled())
logger.debug("Wrote deployment manifest for subsystem {} in state {}", getSymbolicName(), getState());
}
finally {
IOUtils.close(out);
}
}
void setState(State value) {
if (logger.isDebugEnabled())
logger.debug("Setting state of subsystem {} to {}", getSymbolicName(), value);
State state = getState();
if (value.equals(state)) {
if (logger.isDebugEnabled())
logger.debug("Requested state {} equals current state {}", value, state);
return;
}
try {
if (logger.isDebugEnabled())
logger.debug("Setting the deployment manifest...");
synchronized (this) {
setDeploymentManifest(new DeploymentManifest.Builder()
.manifest(getDeploymentManifest()).state(value).build());
}
} catch (Exception e) {
throw new SubsystemException(e);
}
Activator.getInstance().getSubsystemServiceRegistrar().update(this);
synchronized (this) {
if (logger.isDebugEnabled())
logger.debug("Notifying all waiting for state change of subsystem {}", getSymbolicName());
notifyAll();
}
}
void setRegionContextBundle(Bundle value) {
regionContextBundle = value; // volatile variable
}
synchronized void setSubsystemManifest(SubsystemManifest value) throws URISyntaxException, IOException {
File file = new File(getDirectory(), "OSGI-INF");
if (!file.exists())
file.mkdirs();
FileOutputStream fos = new FileOutputStream(new File(file, "SUBSYSTEM.MF"));
try {
value.write(fos);
subsystemManifest = value;
}
finally {
IOUtils.close(fos);
}
}
private final ReentrantLock stateChangeLock = new ReentrantLock();
ReentrantLock stateChangeLock() {
return stateChangeLock;
}
private String getDeploymentManifestHeaderValue(String name) {
DeploymentManifest manifest = getDeploymentManifest();
if (manifest == null)
return null;
Header<?> header = manifest.getHeaders().get(name);
if (header == null)
return null;
return header.getValue();
}
@Override
public synchronized void addRequirements(Collection<Requirement> requirements) {
// The root subsystem has no requirements (there is no parent to import from).
if (isRoot())
throw new UnsupportedOperationException("The root subsystem does not accept additional requirements");
// Unscoped subsystems import everything already.
if (!isScoped())
return;
RegionUpdater updater = new RegionUpdater(getRegion(), ((BasicSubsystem)getParents().iterator().next()).getRegion());
try {
updater.addRequirements(requirements);
}
catch (Exception e) {
throw new SubsystemException(e);
}
}
@Override
public AriesSubsystem install(String location, IDirectory content) {
return install(location, content, null);
}
@Override
public AriesSubsystem install(String location, IDirectory content, InputStream deploymentManifest) {
try {
return AccessController.doPrivileged(new InstallAction(location, content, this, AccessController.getContext(), deploymentManifest));
}
finally {
IOUtils.close(deploymentManifest);
}
}
private static class SaveManifestParticipant implements Participant {
protected SaveManifestParticipant() {}
@Override
public void ended(Coordination coordination) throws Exception {
if (logger.isDebugEnabled())
logger.debug("Saving deployment manifests because coordination {} ended", coordination.getName());
Map<Class<?>, Object> variables = coordination.getVariables();
Set<BasicSubsystem> dirtySubsystems;
synchronized (variables) {
@SuppressWarnings("unchecked")
Set<BasicSubsystem> temp = (Set<BasicSubsystem>) variables.remove(SaveManifestParticipant.class);
dirtySubsystems = temp == null ? Collections. <BasicSubsystem>emptySet() : temp;
}
for (BasicSubsystem dirtySubsystem : dirtySubsystems) {
if (logger.isDebugEnabled())
logger.debug("Saving deployment manifest of subsystem {} for coordination {}", dirtySubsystem.getSymbolicName(), coordination.getName());
dirtySubsystem.saveDeploymentManifest();
}
}
@Override
public void failed(Coordination coordination) throws Exception {
// Do no saving
}
}
@Override
public Map<String, String> getDeploymentHeaders() {
SecurityManager.checkMetadataPermission(this);
return AccessController.doPrivileged(new GetDeploymentHeadersAction(this));
}
@Override
public AriesSubsystem install(String location, final InputStream content, InputStream deploymentManifest) {
AriesSubsystem result = null;
IDirectory directory = null;
try {
directory = content == null ? null :
AccessController.doPrivileged(new PrivilegedAction<IDirectory>() {
@Override
public IDirectory run() {
return FileSystem.getFSRoot(content);
}
});
result = install(location, directory, deploymentManifest);
return result;
}
finally {
// This method must guarantee the content input stream was closed.
// TODO Not sure closing the content is necessary. The content will
// either be null of will have been closed while copying the data
// to the temporary file.
IOUtils.close(content);
// If appropriate, delete the temporary file. Subsystems having
// apache-aries-provision-dependencies:=resolve may need the file
// at start time if it contains any dependencies.
if (directory instanceof ICloseableDirectory) {
if (result == null
|| Utils.isProvisionDependenciesInstall((BasicSubsystem)result)
|| !wasInstalledWithChildrenHavingProvisionDependenciesResolve()) {
final IDirectory toClose = directory;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
((ICloseableDirectory) toClose).close();
}
catch (IOException ioex) {
logger.info("Exception calling close for content {}. Exception {}",
content, ioex);
}
return null;
}
});
}
}
}
}
private void setTranslations() throws IOException {
String directoryName = getSubsystemManifest().getSubsystemLocalizationHeader().getDirectoryName();
File file = directoryName == null ? getDirectory() : new File(getDirectory(), directoryName);
if (!file.exists())
file.mkdirs();
for (TranslationFile translation : getResource().getTranslations()) {
translation.write(file);
}
}
void computeDependenciesPostInstallation(Coordination coordination) throws IOException {
resource.computeDependencies(null, coordination);
ProvisionResourceHeader header = resource.computeProvisionResourceHeader();
setDeploymentManifest(
new DeploymentManifest.Builder()
.manifest(deploymentManifest)
.header(header)
.build());
}
private boolean wasInstalledWithChildrenHavingProvisionDependenciesResolve() {
return wasInstalledWithChildrenHavingProvisionDependenciesResolve(this);
}
private static boolean wasInstalledWithChildrenHavingProvisionDependenciesResolve(Subsystem child) {
BasicSubsystem bs = (BasicSubsystem) child;
SubsystemManifest manifest = bs.getSubsystemManifest();
SubsystemTypeHeader header = manifest.getSubsystemTypeHeader();
AriesProvisionDependenciesDirective directive = header.getAriesProvisionDependenciesDirective();
if (directive.isResolve()) {
return true;
}
return wasInstalledWithChildrenHavingProvisionDependenciesResolve(child.getChildren());
}
private static boolean wasInstalledWithChildrenHavingProvisionDependenciesResolve(Collection<Subsystem> children) {
for (Subsystem child : children) {
if (wasInstalledWithChildrenHavingProvisionDependenciesResolve(child)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return new StringBuilder()
.append(getClass().getName())
.append(": ")
.append("children=")
.append(getChildren().size())
.append(", constituents=")
.append(getConstituents().size())
.append(", id=")
.append(getSubsystemId())
.append(", location=")
.append(getLocation())
.append(", parents=")
.append(getParents().size())
.append(", state=")
.append(getState())
.append(", symbolicName=")
.append(getSymbolicName())
.append(", type=")
.append(getType())
.append(", version=")
.append(getVersion())
.toString();
}
}