/*
* 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.
*/
/*
* SimpleCALFileVault.java
* Creation date: Jul 30, 2004.
* By: Edward Lam
*/
package org.openquark.cal.services;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.ModuleSourceDefinition;
import org.openquark.cal.compiler.SourceModel;
import org.openquark.cal.compiler.SourceModelUtilities;
import org.openquark.cal.metadata.MetadataStore;
import org.openquark.util.EmptyIterator;
/**
* A Vault which wraps a module specified by a simple .cal file.
* @author Edward Lam
*/
public class SimpleCALFileVault extends StoreBasedVault {
/** The name of the module. */
private final ModuleName moduleName;
/** The path to the module. */
private final String locationString;
/** The stored module returned by the vault. */
private final StoredVaultElement.Module storedModule;
/** The vault provider for this class. */
private static final VaultProvider vaultProvider = new VaultProvider() {
/**
* {@inheritDoc}
*/
public String getVaultDescriptor() {
return "SimpleCALFile";
}
/**
* {@inheritDoc}
*/
public Vault getVault(String locationString, VaultAuthenticationManager authenticationManager) {
if (locationString == null) {
return null;
}
File file = WorkspaceLoader.fileFromPath(locationString);
if (file == null) {
return null;
}
ModuleName moduleName = null;
// figure out the module name by reading the file, parsing it, and finding out through the source model
try {
FileReader reader = new FileReader(file);
try {
StringBuilder builder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line).append('\n');
}
String source = builder.toString();
SourceModel.ModuleDefn moduleDefn = SourceModelUtilities.TextParsing.parseModuleDefnIntoSourceModel(source);
if (moduleDefn != null) {
moduleName = SourceModel.Name.Module.toModuleName(moduleDefn.getModuleName());
}
} finally {
reader.close();
}
} catch (IOException e) {
return null;
}
if (moduleName == null) {
return null;
}
CALSourceStore sourceStore = getSourceStore(locationString, moduleName);
if (sourceStore == null) {
return null;
}
return new SimpleCALFileVault(moduleName, locationString, sourceStore);
}
};
/**
* A CALSourceStore based on a single file.
* @author Edward Lam
*/
private static final class CALFileSourceStore implements CALSourceStore {
/** The name of the module represented by the file.*/
private final ModuleName moduleName;
/** The file itself. */
private final File calSourceFile;
/**
* Constructor for a CALFileSourceStore.
* @param moduleName the name of the module represented by the file.
* @param calSourceFile the file containing the source definition.
*/
private CALFileSourceStore(ModuleName moduleName, File calSourceFile) {
this.moduleName = moduleName;
this.calSourceFile = calSourceFile;
}
/**
* Get the module name from the resource identifier for a module.
* @param resourceName the resource name whose feature name corresponds to a module name.
* @return the corresponding module name.
* @throws IllegalArgumentException if the feature name does not correspond to a module name.
*/
private ModuleName checkModuleName(ResourceName resourceName) {
FeatureName featureName = resourceName.getFeatureName();
if (featureName.getType() != CALFeatureName.MODULE) {
throw new IllegalArgumentException("The given feature does not correspond to a module name.");
}
return ((CALFeatureName)featureName).toModuleName();
}
/**
* {@inheritDoc}
*/
public InputStream getInputStream(ResourceName resourceName) {
ModuleName moduleName = checkModuleName(resourceName);
if (calSourceFile == null || !this.moduleName.equals(moduleName)) {
return null;
}
try {
return new FileInputStream(calSourceFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* {@inheritDoc}
*/
public OutputStream getOutputStream(ResourceName resourceName, Status status) {
ModuleName moduleName = checkModuleName(resourceName);
if (calSourceFile == null || !this.moduleName.equals(moduleName)) {
return null;
}
try {
return new FileOutputStream(calSourceFile);
} catch (FileNotFoundException e) {
status.add(new Status(Status.Severity.ERROR, "CAL source for module " + moduleName + " not writeable.", e));
return null;
}
}
/**
* {@inheritDoc}
*/
public String getDebugInfo(ResourceName resourceName) {
ModuleName moduleName = checkModuleName(resourceName);
if (calSourceFile == null || !this.moduleName.equals(moduleName)) {
return null;
}
return "from SimpleCALFile: " + calSourceFile.getAbsolutePath();
}
/**
* {@inheritDoc}
*/
public boolean hasFeature(ResourceName resourceName) {
ModuleName moduleName = checkModuleName(resourceName);
return calSourceFile != null && calSourceFile.exists() && this.moduleName.equals(moduleName);
}
/**
* {@inheritDoc}
*/
public Set<ModuleName> getModuleNames() {
return Collections.singleton(moduleName);
}
/**
* {@inheritDoc}
*/
public Iterator<WorkspaceResource> getResourceIterator() {
return EmptyIterator.emptyIterator();
}
/**
* {@inheritDoc}
*/
public Iterator<WorkspaceResource> getResourceIterator(ModuleName moduleName) {
return EmptyIterator.emptyIterator();
}
/**
* {@inheritDoc}
*/
public void removeResource(ResourceName resourceName, Status removeStatus) {
removeStatus.add(new Status(Status.Severity.ERROR, "Cannot remove source from this location."));
}
/**
* {@inheritDoc}
*/
public void removeModuleResources(ModuleName moduleName, Status removeStatus) {
removeStatus.add(new Status(Status.Severity.ERROR, "Cannot remove source for module " + moduleName + " from this location."));
}
/**
* {@inheritDoc}
*/
public void removeAllResources(Status removeStatus) {
// What to do..?
removeStatus.add(new Status(Status.Severity.ERROR, "Cannot remove source from this location."));
}
/**
* {@inheritDoc}
*/
public boolean renameResource(ResourceName oldResourceName, ResourceName newResourceName, ResourceStore newResourceStore, Status renameStatus) {
// Renaming is not supported with this class.
renameStatus.add(new Status(Status.Severity.ERROR, "Cannot rename a source at this location."));
return false;
}
/**
* {@inheritDoc}
*/
public long getTimeStamp(ResourceName resourceName) {
ModuleName moduleName = checkModuleName(resourceName);
if (calSourceFile != null && this.moduleName.equals(moduleName)) {
return calSourceFile.lastModified();
}
return -1;
}
/**
* {@inheritDoc}
*/
public boolean isWriteable() {
return true;
}
/**
* {@inheritDoc}
*/
public boolean isWriteable(ResourceName resourceName) {
ModuleName moduleName = checkModuleName(resourceName);
if (calSourceFile != null && this.moduleName.equals(moduleName)) {
return calSourceFile.canWrite();
}
return false;
}
/**
* {@inheritDoc}
*/
public boolean isRemovable(ResourceName resourceName) {
return isWriteable(resourceName);
}
/**
* {@inheritDoc}
*/
public String getResourceType() {
return ModuleSourceDefinition.RESOURCE_TYPE;
}
/**
* {@inheritDoc}
*/
public List<ResourceName> getModuleResourceNameList(ModuleName moduleName) {
if (this.moduleName.equals(moduleName)) {
return Collections.singletonList(new ResourceName(CALFeatureName.getModuleFeatureName(moduleName)));
}
return Collections.emptyList();
}
}
/**
* A stored module containing a single source definition.
* @author Edward Lam
*/
private final class StoredModule implements StoredVaultElement.Module {
private final ModuleName moduleName;
private final ModuleSourceDefinition sourceDefinition;
/**
* Constructor for a StoredModule.
* @param moduleName the name of the module.
* @param sourceDefinition the source definition for the module.
*/
private StoredModule(ModuleName moduleName, ModuleSourceDefinition sourceDefinition) {
this.moduleName = moduleName;
this.sourceDefinition = sourceDefinition;
}
/**
* {@inheritDoc}
*/
public String getName() {
return moduleName.toSourceText();
}
/**
* {@inheritDoc}
*/
public ResourceRevision.Info getResourceRevisionInfo() {
String resourceType = ModuleSourceDefinition.RESOURCE_TYPE;
CALFeatureName featureName = CALFeatureName.getModuleFeatureName(moduleName);
ResourceIdentifier identifier = ResourceIdentifier.make(resourceType, featureName);
long revision = sourceDefinition.getTimeStamp();
ResourceRevision resourceRevision = new ResourceRevision(identifier, revision);
return new ResourceRevision.Info(Collections.singletonList(resourceRevision));
}
/**
* {@inheritDoc}
*/
public Iterator<WorkspaceResource> getResourceIterator() {
return Collections.<WorkspaceResource>singletonList(sourceDefinition).iterator();
}
/**
* {@inheritDoc}
*/
public VaultElementInfo getVaultInfo() {
return VaultElementInfo.makeBasic(getVaultProvider().getVaultDescriptor(),
getName(),
SimpleCALFileVault.this.locationString,
0);
}
}
/**
* An empty module resource store for metadata.
* @author Edward Lam
*/
private static class EmptyMetadataStore extends EmptyResourceStore.Module implements MetadataStore {
/**
* Constructor for an EmptyMetadataStore.
*/
EmptyMetadataStore() {
super(WorkspaceResource.METADATA_RESOURCE_TYPE);
}
/**
* {@inheritDoc}
*/
public List<ResourceName> getMetadataResourceNamesForAllLocales(CALFeatureName featureName) {
return Collections.emptyList();
}
}
/**
* An empty module resource store for gem designs.
* @author Edward Lam
*/
private static class EmptyGemDesignStore extends EmptyResourceStore.Module implements GemDesignStore {
/**
* Constructor for an EmptyGemDesignStore.
*/
EmptyGemDesignStore() {
super(WorkspaceResource.GEM_DESIGN_RESOURCE_TYPE);
}
}
/**
* An empty resource store for workspace declarations.
* @author Edward Lam
*/
private static class EmptyWorkspaceDeclarationStore extends EmptyResourceStore.Workspace implements WorkspaceDeclarationStore {
/**
* Constructor for a EmptyWorkspaceDeclarationStore.
*/
EmptyWorkspaceDeclarationStore() {
super(WorkspaceResource.WORKSPACE_DECLARATION_RESOURCE_TYPE);
}
}
/**
* An empty resource store for CAL Archives (Cars).
*
* @author Joseph Wong
*/
private static class EmptyCarStore extends EmptyResourceStore.Car implements CarStore {
/**
* Constructor for a EmptyCarStore.
*/
EmptyCarStore() {
super(WorkspaceResource.CAR_RESOURCE_TYPE);
}
}
/**
* An empty resource store for user resources.
*
* @author Joseph Wong
*/
private static class EmptyUserResourceStore extends EmptyResourceStore.Module implements UserResourceStore {
/**
* Constructor for a EmptyUserResourceStore.
*/
EmptyUserResourceStore() {
super(WorkspaceResource.USER_RESOURCE_TYPE);
}
}
/** A metadata store which doesn't contain any metadata. */
private static final MetadataStore metadataStore = new EmptyMetadataStore();
/** A design store which doesn't contain any designs. */
private static final GemDesignStore designStore = new EmptyGemDesignStore();
/** A workspace declaration store which doesn't contain any workspace declarations. */
private static final WorkspaceDeclarationStore workspaceDeclarationStore = new EmptyWorkspaceDeclarationStore();
/** A Car store which doesn't contain any Cars. */
private static final CarStore carStore = new EmptyCarStore();
/** A user resource store which doesn't contain any user resources. */
private static final UserResourceStore userResourceStore = new EmptyUserResourceStore();
/**
* Constructor for a SimpleCALFileVault.
* Obtain instances via the provider.
*/
private SimpleCALFileVault(final ModuleName moduleName, String storedModulePath, CALSourceStore sourceStore) {
super(sourceStore, metadataStore, designStore, workspaceDeclarationStore, carStore, userResourceStore);
this.locationString = storedModulePath;
this.moduleName = moduleName;
ModuleSourceDefinition sourceDefinition = new FilePathModuleSourceDefinition(storedModulePath, moduleName);
this.storedModule = new StoredModule(moduleName, sourceDefinition);
}
/**
* Get the source store for a module.
* @param storedModulePath the path to the module.
* @param aModuleName the name of the module.
* @return the source store for the module, or null of the path is invalid.
*/
private static CALSourceStore getSourceStore(String storedModulePath, ModuleName aModuleName) {
File fileFromLine = WorkspaceLoader.fileFromPath(storedModulePath);
if (fileFromLine == null) {
String errorString = "WorkspaceLoader: \"" + storedModulePath + "\" is not a valid file path.\n" +
"File paths must be specified either as a path or as a URL.";
CALWorkspace.SERVICES_LOGGER.log(Level.WARNING, errorString);
return null;
}
return new CALFileSourceStore(aModuleName, fileFromLine);
}
/**
* Get an instance of this class by path.
* @param filePath the path to the file.
* @return a Vault which wraps the module specified by the given file.
*/
public static SimpleCALFileVault getSimpleCALFileVault(String filePath) {
return (SimpleCALFileVault)getVaultClassProvider().getVault(filePath, null);
}
/**
* Get an instance of this class by file.
* @param file the file.
* @return a Vault which wraps the module specified by the given file.
*/
public static SimpleCALFileVault getSimpleCALFileVault(File file) {
String pathString = file.toURI().toASCIIString();
return getSimpleCALFileVault(pathString);
}
/**
* {@inheritDoc}
*/
@Override
public int putStoredModule(ModuleName moduleName, CALWorkspace workspace, Status putStatus) {
// Check that the module is the one we accept.
if (!moduleName.equals(this.moduleName)) {
String message = "Cannot export module " + moduleName + " to this vault.\n" +
"This vault only accepts the " + this.moduleName + " module.";
putStatus.add(new Status(Status.Severity.ERROR, message, null));
}
// Warn that designs and metadata aren't saved.
putStatus.add(new Status(Status.Severity.WARNING, "Designs and metadata not saved.", null));
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public StoredVaultElement.Module getStoredModule(ModuleName moduleName, int revisionNumber, Status status) {
if (!moduleName.equals(this.moduleName)) {
return null;
}
return storedModule;
}
/**
* {@inheritDoc}
*/
public VaultProvider getVaultProvider() {
return getVaultClassProvider();
}
/**
* Get the VaultProvider for this class.
* @return the VaultProvider for this class.
*/
public static VaultProvider getVaultClassProvider() {
return vaultProvider;
}
/**
* @return the name of the module specified by the file wrapped by this vault.
*/
public ModuleName getModuleName() {
return moduleName;
}
/**
* {@inheritDoc}
*/
public String getLocationString() {
return locationString;
}
}