/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* StoreBasedVault.java
* Creation date: Jul 30, 2004.
* By: Edward Lam
*/
package org.openquark.cal.services;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.ModuleSourceDefinition;
import org.openquark.cal.metadata.MetadataManager;
import org.openquark.cal.metadata.MetadataStore;
import org.openquark.util.EmptyIterator;
import org.openquark.util.IteratorChain;
/**
* A StoreBasedVault stores and retrieves module resources using resource stores for each type of resource.
* @author Edward Lam
*/
public abstract class StoreBasedVault implements Vault {
/** The Resource manager registry */
private final ResourceManagerRegistry resourceManagerRegistry;
/**
* A stored module from this Vault.
* @author Edward Lam
*/
private class StoreBasedStoredModule implements StoredVaultElement.Module {
private final ModuleName moduleName;
private final int revisionNumber;
/**
* Constructor for a StoreBasedStoredModule.
* @param moduleName the name of the module represented by this stored module.
* @param revisionNumber the revision number assigned to this stored module.
*/
StoreBasedStoredModule(ModuleName moduleName, int revisionNumber) {
this.moduleName = moduleName;
this.revisionNumber = revisionNumber;
}
/**
* {@inheritDoc}
*/
public String getName() {
return moduleName.toSourceText();
}
/**
* {@inheritDoc}
*/
public ResourceRevision.Info getResourceRevisionInfo() {
List<ResourceRevision> revisionList = new ArrayList<ResourceRevision>();
for (Iterator<WorkspaceResource> it = getResourceIterator(); it.hasNext(); ) {
WorkspaceResource workspaceResource = it.next();
ResourceIdentifier resourceIdentifier = workspaceResource.getIdentifier();
long revisionNum = workspaceResource.getTimeStamp();
ResourceRevision resourceRevision = new ResourceRevision(resourceIdentifier, revisionNum);
revisionList.add(resourceRevision);
}
return new ResourceRevision.Info(revisionList);
}
/**
* {@inheritDoc}
*/
public Iterator<WorkspaceResource> getResourceIterator() {
return StoreBasedVault.this.getModuleResourceIterator(moduleName);
}
/**
* {@inheritDoc}
*/
public VaultElementInfo getVaultInfo() {
return StoreBasedVault.this.getVaultInfo(getName(), revisionNumber);
}
}
/**
* A stored workspace declaration from this Vault.
* @author Edward Lam
*/
private class StoreBasedWorkspaceDeclaration implements StoredVaultElement.WorkspaceDeclaration {
private final WorkspaceDeclarationFeatureName workspaceDeclarationName;
private final int revisionNumber;
/**
* Constructor for a StoreBasedWorkspaceDeclaration.
* @param workspaceDeclarationName
* @param revisionNumber the revision number assigned to this stored module.
*/
StoreBasedWorkspaceDeclaration(String workspaceDeclarationName, int revisionNumber) {
this.revisionNumber = revisionNumber;
this.workspaceDeclarationName = WorkspaceDeclarationFeatureName.getWorkspaceDeclarationFeatureName(workspaceDeclarationName);
}
/**
* {@inheritDoc}
*/
public InputStream getInputStream() {
WorkspaceDeclarationManager workspaceDeclarationManager = resourceManagerRegistry.getWorkspaceDeclarationManager();
return workspaceDeclarationManager.getResourceStore().getInputStream(new ResourceName(workspaceDeclarationName));
}
/**
* {@inheritDoc}
*/
public String getName() {
return workspaceDeclarationName.getName();
}
/**
* {@inheritDoc}
*/
public VaultElementInfo getVaultInfo() {
return StoreBasedVault.this.getVaultInfo(getName(), revisionNumber);
}
}
/**
* A stored CAL Archive (Car) from this Vault.
*
* @author Joseph Wong
*/
private static class StoreBasedCar implements StoredVaultElement.Car {
/**
* The CarVault that corresponds to this Car. A Car file is at the same time both a resource and a vault (i.e.
* it is a container of other resources).
*/
private final CarVault carVault;
/**
* Factory method for constructing an instance of StoreBasedCar.
*
* @param outerVault the outer vault which contains the Car.
* @param carName the name of the Car.
* @param revisionNumber the revision number of the Car.
* @param status the tracking statuc object.
* @return a StoreBasedCar instance representing the Car, or null if the Car file cannot be accessed.
*/
private static StoreBasedCar make(StoreBasedVault outerVault, String carName, int revisionNumber, Status status) {
CarVault carVault = CarVault.make(outerVault, getVaultInfo(outerVault, carName, revisionNumber), carName, revisionNumber, status);
if (carVault == null) {
return null;
} else {
return new StoreBasedCar(carVault);
}
}
/**
* Private constructor for StoreBasedCar.
* @param carVault the CarVault that corresponds to this Car.
*/
private StoreBasedCar(CarVault carVault) {
if (carVault == null) {
throw new NullPointerException();
}
this.carVault = carVault;
}
////=====================================
/// StoredVaultElement.Car implementation
//
/**
* {@inheritDoc}
*/
public String getName() {
return carVault.getCarFeatureName().getName();
}
/**
* {@inheritDoc}
*/
public VaultElementInfo getVaultInfo() {
return getVaultInfo((StoreBasedVault)carVault.getOuterVault(), getName(), carVault.getCarRevisionNumber());
}
/**
* Returns the vault info for the named Car in its containing vault.
* @param outerVault the outer vault which contains the Car.
* @param carName the name of the Car.
* @param revisionNumber the revision number of the Car.
* @return the vault info for the Car (as a resource in the outer vault).
*/
private static VaultElementInfo.Basic getVaultInfo(StoreBasedVault outerVault, String carName, int revisionNumber) {
return VaultElementInfo.makeBasic(outerVault.getVaultProvider().getVaultDescriptor(),
carName,
outerVault.getLocationString(),
revisionNumber);
}
/**
* {@inheritDoc}
*/
public CarVault getCarVault() {
return carVault;
}
/**
* {@inheritDoc}
*/
public InputStream getWorkspaceSpec(String specName, Status status) {
return carVault.getCarAccessor().getWorkspaceSpec(specName, status);
}
}
/**
* Constructor for a StoreBasedVault.
* @param sourceStore the source store to use.
* @param metadataStore the metadata store to use.
* @param gemDesignStore the design store to use.
* @param workspaceDeclarationStore the workspace declaration store to use.
* @param carStore the Car store to use.
* @param userResourceStore the user resource store to use.
*/
protected StoreBasedVault(CALSourceStore sourceStore, MetadataStore metadataStore,
GemDesignStore gemDesignStore, WorkspaceDeclarationStore workspaceDeclarationStore,
CarStore carStore, UserResourceStore userResourceStore) {
CALSourceManager vaultSourceManager = new CALSourceManager(sourceStore);
MetadataManager vaultMetadataManager = new MetadataManager(metadataStore);
GemDesignManager vaultGemDesignManager = new GemDesignManager(gemDesignStore);
WorkspaceDeclarationManager vaultWorkspaceDeclarationManager = new WorkspaceDeclarationManager(workspaceDeclarationStore);
CarManager vaultCarManager = new CarManager(carStore);
UserResourceManager vaultUserResourceManager = new UserResourceManager(userResourceStore);
resourceManagerRegistry = new ResourceManagerRegistry();
resourceManagerRegistry.registerResourceManager(vaultSourceManager);
resourceManagerRegistry.registerResourceManager(vaultMetadataManager);
resourceManagerRegistry.registerResourceManager(vaultGemDesignManager);
resourceManagerRegistry.registerResourceManager(vaultWorkspaceDeclarationManager);
resourceManagerRegistry.registerResourceManager(vaultCarManager);
resourceManagerRegistry.registerResourceManager(vaultUserResourceManager);
}
/**
* {@inheritDoc}
*/
public int putStoredModule(ModuleName moduleName, CALWorkspace workspace, Status putStatus) {
// Write out the sources.
boolean sourceSaved = saveSource(moduleName, workspace, putStatus);
// If the sources were successfully written, write out the designs and metadata.
if (sourceSaved) {
MetaModule metaModule = workspace.getMetaModule(moduleName);
saveMetadata(metaModule, putStatus);
saveDesigns(metaModule, putStatus);
}
return 0;
}
/**
* Save the source for a given metamodule into the vault.
* @param moduleName the name of the module whose source to save.
* @param workspace the workspace containing the source.
* @param status the tracking status object.
* @return whether the source was successfully saved.
*/
private boolean saveSource(ModuleName moduleName, CALWorkspace workspace, Status status) {
CALSourceManager sourceManager = resourceManagerRegistry.getSourceManager();
if (sourceManager == null) {
status.add(new Status(Status.Severity.WARNING, "No registered source manager for this vault: " + toString(), null));
return false;
}
ModuleSourceDefinition sourceDefinition = workspace.getSourceDefinition(moduleName);
if (sourceManager.importResource(sourceDefinition, status) == null) {
status.add(new Status(Status.Severity.WARNING, "Could not save source for module: " + moduleName, null));
}
return false;
}
/**
* Save the metadata for a given metamodule into the vault.
* @param metaModule the metamodule whose metadata to save.
* @param status the tracking status object.
*/
private void saveMetadata(MetaModule metaModule, Status status) {
MetadataManager metadataManager = resourceManagerRegistry.getMetadataManager();
if (metadataManager == null) {
status.add(new Status(Status.Severity.WARNING, "No registered metadata manager for this vault: " + toString(), null));
return;
}
MetadataStore metadataStore = (MetadataStore)metadataManager.getResourceStore();
// Clear old metadata.
metadataStore.removeModuleResources(metaModule.getName(), status);
// Get the features in the module.
Set<CALFeatureName> moduleFeatureNames = metaModule.getFeatureNames();
// Save metadata for each of the features.
for (final CALFeatureName featureName : moduleFeatureNames) {
List<ResourceName> metadataResourceNames = metaModule.getMetadataResourceNamesForAllLocales(featureName);
for (int i = 0, n = metadataResourceNames.size(); i < n; i++) {
ResourceName resourceName = metadataResourceNames.get(i);
Locale locale = LocalizedResourceName.localeOf(resourceName);
if (!metadataManager.saveMetadata(metaModule.getMetadata(featureName, locale), status)) {
status.add(new Status(Status.Severity.WARNING, "Could not save metadata for feature: " + featureName.toString(), null));
}
}
}
}
/**
* Save the designs for a given metamodule into the vault.
* @param metaModule the metamodule whose designs to save.
* @param status the tracking status object.
*/
private void saveDesigns(MetaModule metaModule, Status status) {
GemDesignManager gemDesignManager = resourceManagerRegistry.getDesignManager();
if (gemDesignManager == null) {
status.add(new Status(Status.Severity.WARNING, "No registered gem design manager for this vault: " + toString(), null));
return;
}
// For now, only functional agents have designs
// Functional agents
int nGemEntities = metaModule.getNGemEntities();
for (int i = 0; i < nGemEntities; i++) {
GemEntity gemEntity = metaModule.getNthGemEntity(i);
GemDesign gemDesign = gemEntity.getDesign(status);
if (gemDesign != null) {
gemDesignManager.saveGemDesign(gemDesign, status);
}
}
}
/**
* {@inheritDoc}
* The revision number is unchecked..
*/
public StoredVaultElement.Module getStoredModule(final ModuleName moduleName, int revisionNumber, Status status) {
if (getSourceStore().hasFeature(new ResourceName(CALFeatureName.getModuleFeatureName(moduleName)))) {
return new StoreBasedStoredModule(moduleName, 0);
}
return null;
}
/**
* @return the backing source store, or null if there isn't one.
*/
CALSourceStore getSourceStore() {
CALSourceManager sourceManager = resourceManagerRegistry.getSourceManager();
if (sourceManager == null) {
return null;
}
return (CALSourceStore)sourceManager.getResourceStore();
}
/**
* @return the associated WorkspaceDeclarationStore, or null if there isn't one.
*/
private WorkspaceDeclarationStore getWorkspaceDeclarationStore() {
WorkspaceDeclarationManager workspaceDeclarationManager = resourceManagerRegistry.getWorkspaceDeclarationManager();
if (workspaceDeclarationManager == null) {
return null;
}
return (WorkspaceDeclarationStore)workspaceDeclarationManager.getResourceStore();
}
/**
* {@inheritDoc}
*/
public int putWorkspaceDeclaration(String workspaceDeclarationName, WorkspaceDeclaration workspaceDeclaration, Status putStatus) {
WorkspaceDeclarationManager workspaceDeclarationManager = resourceManagerRegistry.getWorkspaceDeclarationManager();
if (workspaceDeclarationManager == null) {
putStatus.add(new Status(Status.Severity.WARNING, "No registered workspace declaration manager for this vault: " + toString(), null));
return 0;
}
// TODOEL: Clear the old workspace definition?
// Save the definition.
if (!workspaceDeclarationManager.saveDeclaration(workspaceDeclarationName, workspaceDeclaration, putStatus)) {
putStatus.add(new Status(Status.Severity.WARNING, "Could not save workspace declaration: " + workspaceDeclarationName, null));
}
return 0;
}
/**
* {@inheritDoc}
* The revision number is unchecked..
*/
public StoredVaultElement.WorkspaceDeclaration getWorkspaceDeclaration(String workspaceDeclarationName, int revisionNumber, Status status) {
WorkspaceDeclarationStore workspaceDeclarationStore = getWorkspaceDeclarationStore();
if (workspaceDeclarationStore == null) {
return null;
}
if (workspaceDeclarationStore.hasFeature(new ResourceName(WorkspaceDeclarationFeatureName.getWorkspaceDeclarationFeatureName(workspaceDeclarationName)))) {
return new StoreBasedWorkspaceDeclaration(workspaceDeclarationName, 0);
}
return null;
}
/**
* {@inheritDoc}
*/
public String getWorkspaceDeclarationDebugInfo(String workspaceDeclarationName, int revisionNumber) {
WorkspaceDeclarationStore workspaceDeclarationStore = getWorkspaceDeclarationStore();
if (workspaceDeclarationStore == null) {
return null;
}
return workspaceDeclarationStore.getDebugInfo(
new ResourceName(WorkspaceDeclarationFeatureName.getWorkspaceDeclarationFeatureName(workspaceDeclarationName)));
}
/**
* {@inheritDoc}
*/
public final ModuleName[] getAvailableModules(Status status) {
Set<ModuleName> moduleNames = getSourceStore().getModuleNames();
return moduleNames.toArray(new ModuleName[moduleNames.size()]);
}
/**
* {@inheritDoc}
*/
public String[] getAvailableWorkspaceDeclarations(Status status) {
WorkspaceDeclarationStore workspaceDeclarationStore = getWorkspaceDeclarationStore();
if (workspaceDeclarationStore == null) {
return null;
}
Set<ResourceName> workspaceNames = workspaceDeclarationStore.getWorkspaceNames();
String[] result = new String[workspaceNames.size()];
int i = 0;
for (final ResourceName resourceName : workspaceNames) {
WorkspaceDeclarationFeatureName featureName = (WorkspaceDeclarationFeatureName)resourceName.getFeatureName();
result[i] = featureName.getName();
i++;
}
return result;
}
/**
* @param moduleName the name of a module in this vault.
* @return An iterator over the resources in this StoredModule.
*/
public Iterator<WorkspaceResource> getModuleResourceIterator(ModuleName moduleName) {
// A list of iterators over ModuleResources.
final List<Iterator<WorkspaceResource>> iteratorList = new ArrayList<Iterator<WorkspaceResource>>();
for (final ResourceManager resourceManager : resourceManagerRegistry.getResourceManagers()) {
if (resourceManager instanceof ModuleResourceManager) {
iteratorList.add(((ResourceStore.Module)resourceManager.getResourceStore()).getResourceIterator(moduleName));
}
}
// Iterator composed of resource store iterators.
return iteratorList.isEmpty() ?
EmptyIterator.<WorkspaceResource>emptyIterator() :
new IteratorChain<WorkspaceResource>(iteratorList);
}
/**
* {@inheritDoc}
*/
public RevisionHistory getModuleRevisionHistory(ModuleName moduleName) {
boolean moduleExists = getSourceStore().hasFeature(new ResourceName(CALFeatureName.getModuleFeatureName(moduleName)));
return getRevisionHistory(moduleExists);
}
/**
* {@inheritDoc}
*/
public RevisionHistory getWorkspaceDeclarationRevisionHistory(String workspaceDeclarationName) {
WorkspaceDeclarationStore workspaceDeclarationStore = getWorkspaceDeclarationStore();
if (workspaceDeclarationStore == null) {
return null;
}
boolean workspaceDeclarationExists =
workspaceDeclarationStore.hasFeature(new ResourceName(WorkspaceDeclarationFeatureName.getWorkspaceDeclarationFeatureName(workspaceDeclarationName)));
return getRevisionHistory(workspaceDeclarationExists);
}
/**
* {@inheritDoc}
*/
public int putCar(Car car, Status putStatus) {
CarManager carManager = resourceManagerRegistry.getCarManager();
if (carManager == null) {
putStatus.add(new Status(Status.Severity.WARNING, "No registered Car manager for this vault: " + toString(), null));
return 0;
}
if (carManager.importResource(car, putStatus) == null) {
putStatus.add(new Status(Status.Severity.WARNING, "Could not save Car: " + car.getName(), null));
}
return 0;
}
/**
* {@inheritDoc}
*/
public StoredVaultElement.Car getCar(String carName, int revisionNumber, Status status) {
CarStore carStore = getCarStore();
if (carStore == null) {
return null;
}
if (carStore.hasFeature(new ResourceName(CarFeatureName.getCarFeatureName(carName)))) {
return StoreBasedCar.make(this, carName, 0, status);
}
return null;
}
/**
* {@inheritDoc}
*/
public String[] getAvailableCars(Status status) {
CarStore carStore = getCarStore();
if (carStore == null) {
return null;
}
Set<ResourceName> carNames = carStore.getCarNames();
String[] result = new String[carNames.size()];
int i = 0;
for (final ResourceName resourceName : carNames) {
CarFeatureName featureName = (CarFeatureName)resourceName.getFeatureName();
result[i] = featureName.getName();
i++;
}
return result;
}
/**
* {@inheritDoc}
*/
public RevisionHistory getCarRevisionHistory(String carName) {
CarStore carStore = getCarStore();
if (carStore == null) {
return null;
}
boolean carExists = carStore.hasFeature(new ResourceName(CarFeatureName.getCarFeatureName(carName)));
return getRevisionHistory(carExists);
}
/**
* {@inheritDoc}
*/
public Car getCarAsResource(String carName, int revisionNumber, Status status) {
CarStore carStore = getCarStore();
if (carStore == null) {
return null;
}
return carStore.getCar(carName);
}
/**
* @return the associated CarStore, or null if there isn't one.
*/
private CarStore getCarStore() {
CarManager carManager = resourceManagerRegistry.getCarManager();
if (carManager == null) {
return null;
}
return (CarStore)carManager.getResourceStore();
}
/**
* @param resourceExists whether the given resource exists in this vault.
* @return the RevisionHistory for that resource.
* If the resource exists, there will be a single revision which will be 0.
* If the resource does not exist, the root and latest revisions will be -1 and there will be no available revisions.
*/
private RevisionHistory getRevisionHistory(boolean resourceExists) {
if (resourceExists) {
return new RevisionHistory() {
public int getRootRevision() {
return 0;
}
public int getLatestRevision() {
return 0;
}
public int[] getAvailableRevisions() {
return new int[] {0};
}
};
} else {
return new RevisionHistory() {
public int getRootRevision() {
return -1;
}
public int getLatestRevision() {
return -1;
}
public int[] getAvailableRevisions() {
return new int[] {};
}
};
}
}
/**
* Get a vault info for an element in this vault.
* @param elementName the name of the element.
* @param revisionNumber the revision number for the vault element.
* @return vault info for vault elements from this vault.
*/
protected VaultElementInfo getVaultInfo(String elementName, int revisionNumber) {
return VaultElementInfo.makeBasic(getVaultProvider().getVaultDescriptor(),
elementName,
StoreBasedVault.this.getLocationString(),
revisionNumber);
}
}