/*
* Copyright (C) 2010 PIRAmIDE-SP3 authors
*
* 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.
*
* This software consists of contributions made by many individuals,
* listed below:
*
* Author: Aitor Almeida <aitor.almeida@deusto.es>
* Pablo Ordua <pablo.orduna@deusto.es>
* Eduardo Castillejo <eduardo.castillejo@deusto.es>
*
*/
package piramide.multimodal.applicationserver.rest;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.commons.io.FileUtils;
import org.restlet.data.Status;
import org.restlet.resource.ResourceException;
class DirectoriesManager {
private static final String BASE_DIRECTORY = ".piramide";
private static final String APPLICATIONS = "applications";
private static final String PROJECT = "project";
private static final String COMPILATIONS = "compilations";
private static final String CONFIGURATION = "configuration";
private static final String SCRIPT_FILE = "build.xml";
private static final String BINARY_FILE = "app.apk";
private static final String VARIABLES = "variables.txt";
private static final String SOURCE_CODE = "src";
private static final String GENERATED_CODE = "generated";
private final String application;
private final String version;
private final Map<String, String> userVariables;
private String applicationsDirectoryName;
private String applicationDirectoryName;
private String applicationVersionDirectoryName;
private String projectDirectoryName;
private String antScriptFileName;
private String compilationsDirectoryName;
private String configurationDirectoryName;
private String variablesTxtFileName;
private String sourceCodeDirectoryName;
private String generatedCodeDirectoryName;
DirectoriesManager(){
this.application = null;
this.version = null;
this.userVariables = null;
}
DirectoriesManager(String application){
this.application = application;
this.version = null;
this.userVariables = null;
}
DirectoriesManager(String application, String version){
this.application = application;
this.version = version;
this.userVariables = null;
}
DirectoriesManager(String application, String version, Map<String, String> userVariables){
this.application = application;
this.version = version;
this.userVariables = userVariables;
}
String getProjectDirectoryName(){
return this.projectDirectoryName;
}
String getApplicationVersionDirectoryName(){
return this.applicationVersionDirectoryName;
}
String getAntScriptFileName(){
return this.antScriptFileName;
}
String getCompilationsDirectoryName(){
return this.compilationsDirectoryName;
}
String getCompilationDirectoryName(){
final String identifier = createIdentifier(this.userVariables);
return this.compilationsDirectoryName + File.separator + identifier;
}
String getBinaryFileName(){
return getCompilationDirectoryName() + File.separator + BINARY_FILE;
}
String getConfigurationDirectoryName(){
return this.configurationDirectoryName;
}
String getVariablesTxtFileName(){
return this.variablesTxtFileName;
}
String getSourceCodeDirectoryName(){
return this.sourceCodeDirectoryName;
}
String getGeneratedCodeDirectoryName(){
return this.generatedCodeDirectoryName;
}
String [] listApplications(){
final File applicationsDirectory = new File(this.applicationsDirectoryName);
final String [] apps = applicationsDirectory.list();
final List<String> applications = new Vector<String>(apps.length);
for(String app : apps)
if(!app.equals(".svn"))
applications.add(app);
return applications.toArray(new String[]{});
}
String [] listVersions(){
final File applicationDirectory = new File(this.applicationDirectoryName);
final String [] vers = applicationDirectory.list();
final List<String> versions = new Vector<String>(vers.length);
for(String ver : vers)
if(!ver.equals(".svn"))
versions.add(ver);
return versions.toArray(new String[]{});
}
boolean binaryFileExists(){
final File binaryFile = new File(getBinaryFileName());
return binaryFile.exists();
}
void createCompilationDirectory() throws ResourceException {
final String compilationDirectoryName = getCompilationDirectoryName();
final File compilationDirectory = new File(compilationDirectoryName);
if(compilationDirectory.mkdir()){ // Only if I have created the directory
final File projectDirectory = new File(this.projectDirectoryName);
try {
FileUtils.copyDirectory(projectDirectory, compilationDirectory);
} catch (IOException e) {
throw new ResourceException(e);
}
}
}
private String createIdentifier(Map<String, String> userVariables){
final StringBuilder arguments = new StringBuilder();
final List<String> keys = new Vector<String>(this.userVariables.keySet());
Collections.sort(keys);
for(String key : keys){
arguments.append("_");
arguments.append(key);
arguments.append("-");
arguments.append(userVariables.get(key));
}
final StringBuilder builder = new StringBuilder("compilation");
final String arg = arguments.toString();
if(needsToBeEncoded(arg))
builder.append(encode(arg));
else
builder.append(arg);
return builder.toString();
}
private String encode(String arg){
try {
final MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(arg.getBytes());
byte[] md5sum = digest.digest();
final BigInteger bigInt = new BigInteger(1, md5sum);
final String output = bigInt.toString(16);
return output;
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 required: " + e.getMessage(), e);
}
}
private boolean needsToBeEncoded(final String arg) {
boolean needsToBeEncoded = false;
for(char c : arg.toCharArray())
if(!Character.isLetterOrDigit(c) && c != '.' && c != '_' && c != '-')
needsToBeEncoded = true;
return needsToBeEncoded;
}
void loadGlobalStructure() throws ResourceException {
// .piramide exists
final File baseDirectory = new File(BASE_DIRECTORY);
if(!baseDirectory.exists())
representError("PIRAmIDE base directory not found; expected: " + baseDirectory.getAbsolutePath());
// .piramide/configuration exists
final StringBuilder configurationPath = new StringBuilder(BASE_DIRECTORY);
configurationPath.append(File.separator);
configurationPath.append(CONFIGURATION);
final File configurationDirectory = new File(configurationPath.toString());
if(!configurationDirectory.exists())
representError("PIRAmIDE configuration directory not found; expected: " + configurationDirectory.getAbsolutePath());
this.configurationDirectoryName = configurationDirectory.getAbsolutePath();
// .piramide/applications exists
final StringBuilder path = new StringBuilder(BASE_DIRECTORY);
path.append(File.separator);
path.append(APPLICATIONS);
final File applicationsDir = new File(path.toString());
if(!applicationsDir.exists())
representError("PIRAmIDE applications directory not found; expected: " + applicationsDir.getAbsolutePath());
this.applicationsDirectoryName = applicationsDir.getAbsolutePath();
}
void loadApplication() throws ResourceException {
if(this.application == null)
throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Calling loadApplication without providing an application");
loadGlobalStructure();
final StringBuilder path = new StringBuilder(this.applicationsDirectoryName);
// .piramide/applications/{application} exists
path.append(File.separator);
path.append(this.application);
final File applicationDir = new File(path.toString());
if(!applicationDir.exists())
representError("PIRAmIDE concrete application directory not found; expected: " + applicationDir.getAbsolutePath());
this.applicationDirectoryName = applicationDir.getAbsolutePath();
}
private void loadVersion() throws ResourceException {
if(this.version == null)
throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Calling loadVersion without providing an version");
loadApplication();
final StringBuilder path = new StringBuilder(this.applicationDirectoryName);
// .piramide/applications/{application}/{version} exists
path.append(File.separator);
path.append(this.version);
final File applicationVersionDir = new File(path.toString());
if(!applicationVersionDir.exists())
representError("PIRAmIDE concrete application version directory not found; expected: " + applicationVersionDir.getAbsolutePath());
this.applicationVersionDirectoryName = applicationVersionDir.getAbsolutePath();
// .piramide/applications/{application}/{version}/project exists
final StringBuilder projectDirectoryName = new StringBuilder(path.toString());
projectDirectoryName.append(File.separator);
projectDirectoryName.append(PROJECT);
final File projectDir = new File(projectDirectoryName.toString());
if(!projectDir.exists())
representError("PIRAmIDE concrete application version project directory not found; expected: " + projectDir.getAbsolutePath());
this.projectDirectoryName = projectDir.getAbsolutePath();
// .piramide/applications/{application}/{version}/compilations exists and is writable
final StringBuilder compilationsDirectoryName = new StringBuilder(path.toString());
compilationsDirectoryName.append(File.separator);
compilationsDirectoryName.append(COMPILATIONS);
final File compilationsDir = new File(compilationsDirectoryName.toString());
if(!compilationsDir.exists())
representError("PIRAmIDE concrete application compilations directory not found; expected: " + compilationsDir.getAbsolutePath());
if(!compilationsDir.canWrite())
representError("PIRAmIDE concrete application compilations directory not writable in: " + compilationsDir.getAbsolutePath());
this.compilationsDirectoryName = compilationsDir.getAbsolutePath();
// .piramide/applications/{application}/{version}/project/build.xml exists
projectDirectoryName.append(File.separator);
projectDirectoryName.append(SCRIPT_FILE);
final File scriptFile = new File(projectDirectoryName.toString());
if(!scriptFile.exists())
representError("PIRAmIDE concrete application script file not found; expected: " + scriptFile.getAbsolutePath());
this.antScriptFileName = scriptFile.getAbsolutePath();
}
void loadCompilation() throws ResourceException {
if(this.userVariables == null)
throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Calling loadCompilation without providing userVariables");
loadVersion();
final String identifier = createIdentifier(this.userVariables);
createCompilationDirectory();
final String compilationDirectoryName = compilationsDirectoryName + File.separator + identifier + File.separator;
// .piramide/applications/{application}/{version}/compilations/{compilation}/variables.txt; it doesn't matter if it exists or not, we're going to overwrite ti
final StringBuilder variablesFileName = new StringBuilder(compilationDirectoryName);
variablesFileName.append(File.separator);
variablesFileName.append(VARIABLES);
final File variablesFile = new File(variablesFileName.toString());
this.variablesTxtFileName = variablesFile.getAbsolutePath();
// .piramide/applications/{application}/{version}/src exists
final StringBuilder sourceCodeDirectoryName = new StringBuilder(compilationDirectoryName);
sourceCodeDirectoryName.append(File.separator);
sourceCodeDirectoryName.append(SOURCE_CODE);
final File sourceCodeDirectory = new File(sourceCodeDirectoryName.toString());
if(!sourceCodeDirectory.exists())
representError("PIRAmIDE concrete application source directory not found; expected: " + sourceCodeDirectory.getAbsolutePath());
this.sourceCodeDirectoryName = sourceCodeDirectory.getAbsolutePath();
// .piramide/applications/{application}/{version}/src exists
final StringBuilder generatedCodeDirectoryName = new StringBuilder(compilationDirectoryName);
generatedCodeDirectoryName.append(File.separator);
generatedCodeDirectoryName.append(GENERATED_CODE);
final File generatedCodeDirectory = new File(generatedCodeDirectoryName.toString());
generatedCodeDirectory.mkdir();
this.generatedCodeDirectoryName = generatedCodeDirectory.getAbsolutePath();
}
private void representError(String message) throws ResourceException{
throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, message);
}
}
|