Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
otsakir committed Jan 24, 2018
1 parent eba7978 commit 714b9b9
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 131 deletions.
Expand Up @@ -21,6 +21,8 @@
package org.restcomm.connect.rvd.helpers;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -51,10 +53,12 @@
import org.restcomm.connect.rvd.model.project.Step;
import org.restcomm.connect.rvd.model.client.WavItem;
import org.restcomm.connect.rvd.model.project.RvdProject;
import org.restcomm.connect.rvd.storage.FsProjectDao;
import org.restcomm.connect.rvd.storage.FsProjectStorage;
import org.restcomm.connect.rvd.storage.ProjectDao;
import org.restcomm.connect.rvd.storage.WorkspaceStorage;
import org.restcomm.connect.rvd.storage.exceptions.BadProjectHeader;
import org.restcomm.connect.rvd.storage.exceptions.StorageEntityNotFound;
import org.restcomm.connect.rvd.storage.exceptions.ProjectAlreadyExists;
import org.restcomm.connect.rvd.storage.exceptions.StorageException;
import org.restcomm.connect.rvd.storage.exceptions.WavItemDoesNotExist;
import org.restcomm.connect.rvd.upgrade.UpgradeService;
Expand All @@ -70,6 +74,8 @@
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.restcomm.connect.rvd.utils.Zipper;
import org.restcomm.connect.rvd.utils.exceptions.ZipperException;

public class ProjectHelper {

Expand All @@ -81,19 +87,22 @@ public enum Status {
WorkspaceStorage workspaceStorage;
ModelMarshaler marshaler;
String servletContextPath;
ProjectDao projectDao;

public ProjectHelper(RvdContext rvdContext, WorkspaceStorage workspaceStorage) {
public ProjectHelper(RvdContext rvdContext, WorkspaceStorage workspaceStorage, ProjectDao projectDao) {
this.servletContextPath = rvdContext.getServletContext().getContextPath();
this.configuration = rvdContext.getConfiguration();
this.workspaceStorage = workspaceStorage;
this.marshaler = rvdContext.getMarshaler();
this.projectDao = projectDao;
}

public ProjectHelper(RvdConfiguration configuration, WorkspaceStorage workspaceStorage, ModelMarshaler marshaler, String servletContextPath) {
public ProjectHelper(RvdConfiguration configuration, WorkspaceStorage workspaceStorage, ModelMarshaler marshaler, String servletContextPath, ProjectDao projectDao) {
this.configuration = configuration;
this.workspaceStorage = workspaceStorage;
this.marshaler = marshaler;
this.servletContextPath = servletContextPath;
this.projectDao = projectDao;
}

// Used for testing. TODO create a ProjectHelper interface, ProjectServiceBuilder and separate implementation
Expand Down Expand Up @@ -203,24 +212,13 @@ public void updateProject(HttpServletRequest request, String projectName, Projec
state.getHeader().setVersion(configuration.RVD_PROJECT_VERSION);
// preserve project owner
state.getHeader().setOwner(existingProject.getHeader().getOwner());
//projectStorage.storeProject(projectName, state, false);
FsProjectStorage.storeProject(false, state, projectName, workspaceStorage);
projectDao.updateProjectState(projectName, state);

if ( !validationResult.isSuccess() ) {
throw new ValidationException(validationResult);
}
}

public void deleteProject(String projectName) throws ProjectDoesNotExist, StorageException {
if (! FsProjectStorage.projectExists(projectName,workspaceStorage))
throw new ProjectDoesNotExist();
FsProjectStorage.deleteProject(projectName,workspaceStorage);
}

public InputStream archiveProject(String projectName) throws StorageException {
return FsProjectStorage.archiveProject(projectName,workspaceStorage);
}

public void importProjectFromRawArchive(InputStream archiveStream, String applicationSid, String owner) throws RvdException {
File archiveFile = new File(applicationSid);
String projectName = FilenameUtils.getBaseName(archiveFile.getName());
Expand Down Expand Up @@ -261,17 +259,16 @@ public String importProject(File tempProjectDir, String suggestedName, String ow
}
}
// project is either compatible or was upgraded
ProjectState state = FsProjectStorage.loadProject(tempProjectDir.getName(), tempStorage);
ProjectDao tempProjectDao = new FsProjectDao(tempStorage); // this will always happen on the filesystem regardless of implementation of the actual workspace
ProjectState state = tempProjectDao.loadProject(tempProjectDir.getName());
state.getHeader().setOwner(owner);
FsProjectStorage.storeProject(false, state, tempProjectDir.getName(), tempStorage);
projectDao.updateProjectState(tempProjectDir.getName(), state);

// TODO Make these an atomic action!
suggestedName = FsProjectStorage.getAvailableProjectName(suggestedName, workspaceStorage);
FsProjectStorage.createProjectSlot(suggestedName, workspaceStorage);
if ( projectDao.projectExists(suggestedName) )
throw new ProjectAlreadyExists("Project '" + suggestedName + "' already exists");
projectDao.createProjectFromLocation(suggestedName, tempProjectDir.getName(), owner );

FsProjectStorage.importProjectFromDirectory(tempProjectDir, suggestedName, true, workspaceStorage);
return suggestedName;

} catch ( UnsupportedProjectVersion e) {
throw e;
} catch (Exception e) {
Expand All @@ -281,10 +278,6 @@ public String importProject(File tempProjectDir, String suggestedName, String ow
}
}

public void addWavToProject(String projectName, String wavName, InputStream wavStream) throws StorageException, StreamDoesNotFitInFile {
FsProjectStorage.storeWav(projectName, wavName, wavStream, workspaceStorage, configuration.getMaxMediaFileSize());
}

public List<WavItem> getWavs(String appName) throws StorageException {
return FsProjectStorage.listWavs(appName, workspaceStorage);
}
Expand All @@ -301,13 +294,10 @@ public void removeWavFromProject(String projectName, String wavName) throws WavI
*/

public RvdProject load(String projectName) throws RvdException {
String projectJson;
try {
projectJson = FsProjectStorage.loadProjectString(projectName, workspaceStorage);
} catch (StorageEntityNotFound e) {
throw new ProjectDoesNotExist("Error loading project " + projectName, e);
}
RvdProject project = RvdProject.fromJson(projectName, projectJson);
ProjectState projectState = projectDao.loadProject(projectName);
if (projectState == null)
throw new ProjectDoesNotExist("Error loading project " + projectName);
RvdProject project = RvdProject.fromState(projectName, projectState);
return project;
}

Expand Down
Expand Up @@ -17,6 +17,9 @@
import org.restcomm.connect.rvd.model.callcontrol.CallControlAction;
import org.restcomm.connect.rvd.model.callcontrol.CallControlStatus;
import org.restcomm.connect.rvd.model.callcontrol.CreateCallResponse;
import org.restcomm.connect.rvd.storage.FsProjectDao;
import org.restcomm.connect.rvd.storage.ProjectDao;
import org.restcomm.connect.rvd.storage.WorkspaceStorage;
import org.restcomm.connect.rvd.validation.ValidationReport;

import com.google.gson.Gson;
Expand Down Expand Up @@ -126,4 +129,9 @@ protected Response buildWebTriggerJsonResponse(CallControlAction action, CallCon
return Response.status(httpStatus).entity( gson.toJson(response)).type(MediaType.APPLICATION_JSON).build();
}

protected ProjectDao buildProjectDao(WorkspaceStorage storage) {
ProjectDao dao = new FsProjectDao(storage);
return dao;
}

}
Expand Up @@ -40,6 +40,7 @@
import org.restcomm.connect.rvd.restcomm.RestcommApplicationResponse;
import org.restcomm.connect.rvd.restcomm.RestcommApplicationsResponse;
import org.restcomm.connect.rvd.restcomm.RestcommClient;
import org.restcomm.connect.rvd.storage.ProjectDao;
import org.restcomm.connect.rvd.storage.WorkspaceStorage;

import javax.annotation.PostConstruct;
Expand Down Expand Up @@ -70,6 +71,7 @@ public enum NotificationType {
}

private ProjectHelper projectService;
WorkspaceStorage workspaceStorage;

public NotificationsRestService() {
}
Expand All @@ -79,8 +81,8 @@ public void init() {
super.init(); // setup userIdentityContext
logging.appendAccountSid(getUserIdentityContext().getAccountSid());
RvdContext rvdContext = new RvdContext(request, servletContext,applicationContext.getConfiguration(), logging);
WorkspaceStorage storage = new WorkspaceStorage(applicationContext.getConfiguration().getWorkspaceBasePath(), rvdContext.getMarshaler());
projectService = new ProjectHelper(rvdContext, storage);
workspaceStorage = new WorkspaceStorage(applicationContext.getConfiguration().getWorkspaceBasePath(), rvdContext.getMarshaler());
projectService = new ProjectHelper(rvdContext, workspaceStorage, buildProjectDao(workspaceStorage) );
}

// used for testing
Expand Down Expand Up @@ -160,7 +162,8 @@ void processApplicationRemovalNotification(String applicationSid) throws RvdExce
RvdProject project = projectService.load(applicationSid);
if (! getLoggedUsername().equalsIgnoreCase(project.getState().getHeader().getOwner()))
throw new AuthorizationException();
projectService.deleteProject(applicationSid);
ProjectDao projectDao = buildProjectDao(workspaceStorage);
projectDao.removeProject(applicationSid);
}

void processAccountRemovalNotification(String removedAccountSid) throws RvdException {
Expand All @@ -182,7 +185,8 @@ void processAccountRemovalNotification(String removedAccountSid) throws RvdExcep
if (applications != null) {
for (RestcommApplicationResponse app: applications) {
try {
projectService.deleteProject(app.getSid());
ProjectDao projectDao = buildProjectDao(workspaceStorage);
projectDao.removeProject(app.getSid());
} catch (ProjectDoesNotExist e) {
RvdLoggers.global.log(Level.WARN, LoggingHelper.buildMessage(getClass(),"processAccountRemovalNotification","{0} project {1} wasn't removed because it wasn't found", new Object[] {logging.getPrefix(), app.getSid()}));
}
Expand Down
Expand Up @@ -133,7 +133,7 @@ public void init() {
configuration = rvdContext.getConfiguration();
marshaler = rvdContext.getMarshaler();
workspaceStorage = new WorkspaceStorage(configuration.getWorkspaceBasePath(), marshaler);
projectService = new ProjectHelper(rvdContext, workspaceStorage);
projectService = new ProjectHelper(rvdContext, workspaceStorage, buildProjectDao(workspaceStorage)); // TODO this creates duplicate project dao (the other instance is created in each individual method call). We should remove one of them at the end
}

public ProjectRestService() {
Expand Down Expand Up @@ -574,7 +574,8 @@ public Response deleteProject(@PathParam("applicationSid") String applicationSid
try {
ProjectApplicationsApi applicationsApi = new ProjectApplicationsApi(getUserIdentityContext(), applicationContext, restcommBaseUrl);
applicationsApi.removeApplication(applicationSid);
projectService.deleteProject(applicationSid);
ProjectDao dao = buildProjectDao(workspaceStorage);
dao.removeProject(applicationSid);
if (RvdLoggers.local.isEnabledFor(Level.INFO))
RvdLoggers.local.log(Level.INFO, LoggingHelper.buildMessage(getClass(), "deleteProject", logging.getPrefix(), "project removed"));
return Response.ok().build();
Expand Down Expand Up @@ -609,7 +610,7 @@ public Response downloadArchive(@PathParam("applicationSid") String applicationS

InputStream archiveStream;
try {
archiveStream = projectService.archiveProject(applicationSid);
archiveStream = projectDao.archiveProject(applicationSid);
String dispositionHeader = "attachment; filename*=UTF-8''" + RvdUtils.myUrlEncode(projectName + ".zip");
return Response.ok(archiveStream, "application/zip").header("Content-Disposition", dispositionHeader).build();
} catch (StorageException e) {
Expand Down Expand Up @@ -672,7 +673,7 @@ public Response uploadWavFile(@PathParam("applicationSid") String applicationSid
return Response.status(Status.BAD_REQUEST).entity("{\"error\":\"FILE_EXT_NOT_ALLOWED\"}").build();
}
try {
projectService.addWavToProject(applicationSid, filename, item.openStream());
projectDao.storeWav(applicationSid,filename, item.openStream(),configuration.getMaxMediaFileSize());
} catch (StreamDoesNotFitInFile e) {
// Oops, the uploaded file is too big. Back off..
Integer maxSize = rvdContext.getConfiguration().getMaxMediaFileSize();
Expand Down Expand Up @@ -893,8 +894,4 @@ public Response storeProjectParameters(@PathParam("applicationSid") String appli
}
}

protected ProjectDao buildProjectDao(WorkspaceStorage storage) {
ProjectDao dao = new FsProjectDao(storage);
return dao;
}
}
Expand Up @@ -13,6 +13,7 @@
import org.restcomm.connect.rvd.model.stats.AppStatsDto;
import org.restcomm.connect.rvd.stats.AggregateStats;
import org.restcomm.connect.rvd.storage.FsProjectStorage;
import org.restcomm.connect.rvd.storage.ProjectDao;
import org.restcomm.connect.rvd.storage.WorkspaceStorage;
import org.restcomm.connect.rvd.storage.exceptions.StorageException;

Expand Down Expand Up @@ -133,7 +134,8 @@ void checkApplicationAccess(String appId) throws ProjectDoesNotExist, StorageExc
secure();
// make sure the project exists
WorkspaceStorage workspace = new WorkspaceStorage(config.getWorkspaceBasePath(), null); // no need for marshaller for checking project existence
if (! FsProjectStorage.projectExists(appId, workspace))
ProjectDao projectDao = buildProjectDao(workspace);
if (projectDao.projectExists(appId))
throw new ProjectDoesNotExist(appId);
// get project owner
StateHeader projectHeader = FsProjectStorage.loadStateHeader(appId, workspace);
Expand Down
Expand Up @@ -74,8 +74,7 @@ private Node getModule(String searchedName) {
return null;
}

public static RvdProject fromJson(String name, String projectJson) throws RvdException {
ProjectState state = toModel(projectJson);
public static RvdProject fromState(String name, ProjectState state) throws RvdException {
String kind = state.getHeader().getProjectKind();
RvdProject project = null;
if ( "voice".equals(kind) ) {
Expand Down
@@ -1,7 +1,13 @@
package org.restcomm.connect.rvd.storage;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.restcomm.connect.rvd.RvdConfiguration;
import org.restcomm.connect.rvd.exceptions.ProjectDoesNotExist;
import org.restcomm.connect.rvd.exceptions.StreamDoesNotFitInFile;
import org.restcomm.connect.rvd.logging.system.LoggingHelper;
import org.restcomm.connect.rvd.logging.system.RvdLoggers;
import org.restcomm.connect.rvd.model.CallControlInfo;
import org.restcomm.connect.rvd.model.ProjectParameters;
import org.restcomm.connect.rvd.model.ProjectSettings;
Expand All @@ -11,10 +17,16 @@
import org.restcomm.connect.rvd.model.server.ProjectIndex;
import org.restcomm.connect.rvd.storage.exceptions.StorageEntityNotFound;
import org.restcomm.connect.rvd.storage.exceptions.StorageException;
import org.restcomm.connect.rvd.utils.RvdUtils;
import org.restcomm.connect.rvd.utils.Zipper;
import org.restcomm.connect.rvd.utils.exceptions.ZipperException;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
Expand All @@ -25,6 +37,8 @@
*/
public class FsProjectDao implements ProjectDao {

static Logger logger = RvdLoggers.local;

WorkspaceStorage workspaceStorage;

public FsProjectDao(WorkspaceStorage workspaceStorage) {
Expand All @@ -35,6 +49,11 @@ public FsProjectDao(WorkspaceStorage workspaceStorage) {
this.workspaceStorage = workspaceStorage;
}

@Override
public boolean projectExists(String applicationId) {
return workspaceStorage.entityExists(applicationId, "state");
}

@Override
public ProjectState loadProject(String applicationId) throws StorageException {
try {
Expand Down Expand Up @@ -200,6 +219,58 @@ public void storeProjectParameters(String applicationId, ProjectParameters param
workspaceStorage.storeEntity(parameters, ProjectParameters.class, "parameters", applicationId);
}

@Override
public void removeProject(String applicationId) throws ProjectDoesNotExist, StorageException {
FsProjectStorage.deleteProject(applicationId,workspaceStorage);
}

@Override
public void updateProjectState(String applicationId, ProjectState state) throws StorageException {
workspaceStorage.storeEntity(state, "state", applicationId);
}


@Override
public InputStream archiveProject(String projectName) throws StorageException {
String path = workspaceStorage.resolveWorkspacePath(projectName);
File tempFile;
try {
tempFile = File.createTempFile("RVDprojectArchive",".zip");
} catch (IOException e1) {
throw new StorageException("Error creating temp file for archiving project " + projectName, e1);
}

InputStream archiveStream;
try {
Zipper zipper = new Zipper(tempFile);
zipper.addDirectoryRecursively(path, false);
zipper.finish();

// open a stream on this file
archiveStream = new FileInputStream(tempFile);
return archiveStream;
} catch (ZipperException e) {
throw new StorageException( "Error archiving " + projectName, e);
} catch (FileNotFoundException e) {
throw new StorageException("This is weird. Can't find the temp file i just created for archiving project " + projectName, e);
} finally {
// Always delete the file. The underlying file content still exists because the archiveStream refers to it (for Linux only). It will be deleted when the stream is closed
tempFile.delete();
}
}

@Override
public void storeWav(String projectName, String wavname, InputStream wavStream, Integer maxSize) throws StorageException, StreamDoesNotFitInFile {
String wavPathname = workspaceStorage.resolveWorkspacePath(projectName + File.separator + RvdConfiguration.WAVS_DIRECTORY_NAME + File.separator + wavname);
if(logger.isDebugEnabled())
logger.log(Level.DEBUG, LoggingHelper.buildMessage(FsProjectStorage.class,"storeWav", "writing wav file to {0}", wavPathname));
try {
RvdUtils.streamToFile(wavStream, new File(wavPathname), maxSize);
} catch (IOException e) {
throw new StorageException("Error writing to " + wavPathname, e);
}
}

/**
* Generates a list of media files for a project at specific path
*
Expand Down

0 comments on commit 714b9b9

Please sign in to comment.