Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
This refer to BS-156
  • Loading branch information
gvagenas committed Jun 26, 2018
1 parent 455c250 commit ec20791
Show file tree
Hide file tree
Showing 36 changed files with 493 additions and 409 deletions.
Expand Up @@ -37,6 +37,7 @@
import org.restcomm.connect.commons.loader.ObjectFactory;
import org.restcomm.connect.commons.loader.ObjectInstantiationException;
import org.restcomm.connect.commons.util.DNSUtils;
import org.restcomm.connect.core.service.RestcommConnectServiceProvider;
import org.restcomm.connect.dao.DaoManager;
import org.restcomm.connect.dao.entities.InstanceId;
import org.restcomm.connect.dao.entities.Organization;
Expand Down Expand Up @@ -233,10 +234,10 @@ private String home(final ServletContext context) {
}
}

private DaoManager storage(final Configuration configuration, Configuration daoManagerConfiguration, S3AccessTool s3AccessTool, final ClassLoader loader, final ExecutionContext ec) throws ObjectInstantiationException {
private DaoManager storage(final Configuration configuration, Configuration daoManagerConfiguration, final ClassLoader loader) throws ObjectInstantiationException {
final String classpath = daoManagerConfiguration.getString("dao-manager[@class]");
final DaoManager daoManager = (DaoManager) new ObjectFactory(loader).getObjectInstance(classpath);
daoManager.configure(configuration, daoManagerConfiguration, s3AccessTool, ec);
daoManager.configure(configuration, daoManagerConfiguration);
daoManager.start();
return daoManager;
}
Expand Down Expand Up @@ -409,14 +410,15 @@ public void servletInitialized(SipServletContextEvent event) {
// Share the actor system with other servlets.
context.setAttribute(ActorSystem.class.getName(), system);
ec = system.dispatchers().lookup("restcomm-blocking-dispatcher");
context.setAttribute(ExecutionContext.class.getName(), ec);

S3AccessTool s3AccessTool = prepareS3AccessTool(xml);
context.setAttribute(S3AccessTool.class.getName(), s3AccessTool);

// Create the storage system.
DaoManager storage = null;
try {
storage = storage(xml, daoManagerConf, s3AccessTool, loader, ec);
storage = storage(xml, daoManagerConf, loader);
} catch (final ObjectInstantiationException exception) {
logger.error("ObjectInstantiationException during initialization: ", exception);
}
Expand Down
Expand Up @@ -20,12 +20,10 @@
package org.restcomm.connect.commons;

import org.apache.commons.configuration.Configuration;
import org.restcomm.connect.commons.amazonS3.S3AccessTool;
import scala.concurrent.ExecutionContext;

/**
* @author quintana.thomas@gmail.com (Thomas Quintana)
*/
public interface Configurable {
void configure(Configuration configuration, Configuration daoManagerConfiguration, S3AccessTool s3AccessTool, ExecutionContext ec);
void configure(Configuration configuration, Configuration daoManagerConfiguration);
}
7 changes: 6 additions & 1 deletion restcomm/restcomm.core/pom.xml
Expand Up @@ -31,6 +31,11 @@
<groupId>com.googlecode.libphonenumber</groupId>
<artifactId>libphonenumber</artifactId>
</dependency>
</dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>

</project>
@@ -1,24 +1,22 @@
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2018, Telestax Inc and individual contributors
* by the @authors tag.
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2018, Telestax Inc and individual contributors
* by the @authors tag.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.restcomm.connect.application;
package org.restcomm.connect.core.service;

import javax.servlet.ServletContext;

Expand All @@ -31,7 +29,9 @@
import org.restcomm.connect.core.service.number.NumberSelectorServiceImpl;
import org.restcomm.connect.core.service.profile.ProfileServiceImpl;
import org.restcomm.connect.core.service.recording.RecordingsServiceImpl;
import org.restcomm.connect.core.service.util.UriUtils;
import org.restcomm.connect.dao.DaoManager;
import scala.concurrent.ExecutionContext;

/**
* @author guilherme.jansen@telestax.com
Expand All @@ -45,6 +45,7 @@ public class RestcommConnectServiceProvider {
private ProfileService profileService;
private ClientPasswordHashingService clientPasswordHashingService;
private RecordingService recordingService;
private UriUtils uriUtils;

public static RestcommConnectServiceProvider getInstance() {
if (instance == null) {
Expand All @@ -67,9 +68,16 @@ public void startServices(ServletContext ctx) {
ctx.setAttribute(ClientPasswordHashingService.class.getName(), clientPasswordHashingService);

S3AccessTool s3AccessTool = (S3AccessTool) ctx.getAttribute(S3AccessTool.class.getName());
ExecutionContext ec = (ExecutionContext) ctx.getAttribute(ExecutionContext.class.getName());

this.recordingService = new RecordingsServiceImpl(daoManager.getRecordingsDao(), s3AccessTool);
this.uriUtils = new UriUtils(daoManager);
ctx.setAttribute(UriUtils.class.getName(), uriUtils);

this.recordingService = new RecordingsServiceImpl(daoManager.getRecordingsDao(), s3AccessTool, ec, uriUtils);
ctx.setAttribute(RecordingService.class.getName(), recordingService);



}

/**
Expand All @@ -96,4 +104,10 @@ public ProfileService provideProfileService() {
*/
public RecordingService recordingService() { return recordingService; }

/**
*
* @return
*/
public UriUtils uriUtils() { return uriUtils; }

}
Expand Up @@ -20,9 +20,16 @@
package org.restcomm.connect.core.service.api;

import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.dao.entities.MediaAttributes;

import java.net.URI;

public interface RecordingService {

URI storeRecording(Sid recordingSid, MediaAttributes.MediaType mediaType);

URI prepareFileUrl (String apiVersion, String accountSid, String recordingSid, MediaAttributes.MediaType mediaType);

void removeRecording(Sid recordingSid);

}
Expand Up @@ -19,16 +19,23 @@

package org.restcomm.connect.core.service.recording;

import akka.dispatch.Futures;
import org.apache.log4j.Logger;
import org.restcomm.connect.commons.amazonS3.S3AccessTool;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.core.service.api.RecordingService;
import org.restcomm.connect.core.service.util.UriUtils;
import org.restcomm.connect.dao.RecordingsDao;
import org.restcomm.connect.dao.entities.MediaAttributes;
import org.restcomm.connect.dao.entities.Recording;
import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.Callable;

public class RecordingsServiceImpl implements RecordingService {

Expand All @@ -37,18 +44,56 @@ public class RecordingsServiceImpl implements RecordingService {
private final RecordingsDao recordingsDao;
private final S3AccessTool s3AccessTool;
private String recordingsPath;
private ExecutionContext ec;
private UriUtils uriUtils;

public RecordingsServiceImpl (RecordingsDao recordingsDao, S3AccessTool s3AccessTool) {
public RecordingsServiceImpl (RecordingsDao recordingsDao, S3AccessTool s3AccessTool, ExecutionContext ec, UriUtils uriUtils) {
this.recordingsDao = recordingsDao;
this.s3AccessTool = s3AccessTool;
this.recordingsPath = RestcommConfiguration.getInstance().getMain().getRecordingPath();
this.ec = ec;
this.uriUtils = uriUtils;
}

//Used for unit testing
public RecordingsServiceImpl (RecordingsDao recordingsDao, S3AccessTool s3AccessTool, String recordingsPath) {
public RecordingsServiceImpl (RecordingsDao recordingsDao, String recordingsPath, S3AccessTool s3AccessTool, ExecutionContext ec, UriUtils uriUtils) {
this.recordingsDao = recordingsDao;
this.s3AccessTool = s3AccessTool;
this.recordingsPath = recordingsPath;
this.ec = ec;
this.uriUtils = uriUtils;
}

@Override
public URI storeRecording (final Sid recordingSid, MediaAttributes.MediaType mediaType) {
URI s3Uri = null;
final String fileExtension = mediaType.equals(MediaAttributes.MediaType.AUDIO_ONLY) ? ".wav" : ".mp4";
Recording recording = recordingsDao.getRecording(recordingSid);
if (s3AccessTool != null && ec != null) {
s3Uri = s3AccessTool.getS3Uri(recordingsPath+"/"+recordingSid+fileExtension);
Future<Boolean> f = Futures.future(new Callable<Boolean>() {
@Override
public Boolean call () throws Exception {
return s3AccessTool.uploadFile(recordingsPath+"/"+recordingSid+fileExtension);
}
}, ec);
}

return s3Uri;
}

@Override
public URI prepareFileUrl(String apiVersion, String accountSid, String recordingSid, MediaAttributes.MediaType mediaType) {
final String fileExtension = mediaType.equals(MediaAttributes.MediaType.AUDIO_ONLY) ? ".wav" : ".mp4";
String fileUrl = String.format("/restcomm/%s/Accounts/%s/Recordings/%s",apiVersion,accountSid,recordingSid);
URI uriToResolve = null;
try {
//For local stored recordings, add .wav/.mp4 suffix to the URI
uriToResolve = new URI(fileUrl+fileExtension);
} catch (URISyntaxException e) {
logger.error(e);
}
return uriUtils.resolve(uriToResolve, new Sid(accountSid));
}

@Override
Expand Down
Expand Up @@ -31,9 +31,11 @@
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.HttpConnectorList;
import org.restcomm.connect.commons.annotations.concurrency.ThreadSafe;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.util.DNSUtils;
import org.restcomm.connect.commons.util.JBossConnectorDiscover;
import org.restcomm.connect.commons.util.TomcatConnectorDiscover;
import org.restcomm.connect.dao.DaoManager;

/**
* Utility class to manipulate URI.
Expand All @@ -43,14 +45,15 @@
@ThreadSafe
public final class UriUtils {

private static Logger logger = Logger.getLogger(UriUtils.class);
private static HttpConnector selectedConnector = null;
private Logger logger = Logger.getLogger(UriUtils.class);
private HttpConnector selectedConnector = null;
private DaoManager daoManager;

/**
* Default constructor.
*/
private UriUtils() {
super();
public UriUtils(final DaoManager daoManager) {
this.daoManager = daoManager;
}

/**
Expand All @@ -60,7 +63,7 @@ private UriUtils() {
* @param uri The relative URI.
* @return The absolute URI
*/
public static URI resolve(final URI base, final URI uri) {
public URI resolveWithBase (final URI base, final URI uri) {
if (base.equals(uri)) {
return uri;
} else if (!uri.isAbsolute()) {
Expand All @@ -78,7 +81,7 @@ public static URI resolve(final URI base, final URI uri) {
*
* @return the list of connectors found
*/
private static HttpConnectorList getHttpConnectors() throws Exception {
private HttpConnectorList getHttpConnectors() throws Exception {
logger.info("Searching HTTP connectors.");
HttpConnectorList httpConnectorList = null;
//find Jboss first as is typical setup
Expand All @@ -91,41 +94,57 @@ private static HttpConnectorList getHttpConnectors() throws Exception {
}

/**
* Resolves a relative URI.
*
* Use to resolve a relative URI
* using the instance hostname as base
*
* @param uri
* @return
*/
public URI resolve(final URI uri) {
return resolve(uri, null);
}

/**
* Use to resolve a relative URI
* using the domain name of the Organization
* that the provided AccountSid belongs
*
* @param uri The relative URI
* @param accountSid The accountSid to get the Org domain
* @return The absolute URI
*/
public static URI resolve(final URI uri) {
public URI resolve(final URI uri, final Sid accountSid) {
getHttpConnector();

// Since this is a relative URL that we are trying to resolve, we don't care about the public URL.
// //HttpConnector address could be a local address while the request came from a public address
// String address;
// if (httpConnector.getAddress().equalsIgnoreCase(localAddress)) {
// address = httpConnector.getAddress();
// } else {
// address = localAddress;
// }
String restcommAddress = null;
if (RestcommConfiguration.getInstance().getMain().isUseHostnameToResolveRelativeUrls()) {
restcommAddress = RestcommConfiguration.getInstance().getMain().getHostname();
if (restcommAddress == null || restcommAddress.isEmpty()) {
try {
InetAddress addr = DNSUtils.getByName(selectedConnector.getAddress());
restcommAddress = addr.getCanonicalHostName();
} catch (UnknownHostException e) {
logger.error("Unable to resolve: " + selectedConnector + " to hostname: " + e);
restcommAddress = selectedConnector.getAddress();

if (accountSid != null && daoManager != null) {
Sid organizationSid = daoManager.getAccountsDao().getAccount(accountSid).getOrganizationSid();
restcommAddress = daoManager.getOrganizationsDao().getOrganization(organizationSid).getDomainName();
}

if (restcommAddress == null || restcommAddress.isEmpty()) {
if (RestcommConfiguration.getInstance().getMain().isUseHostnameToResolveRelativeUrls()) {
restcommAddress = RestcommConfiguration.getInstance().getMain().getHostname();
if (restcommAddress == null || restcommAddress.isEmpty()) {
try {
InetAddress addr = DNSUtils.getByName(selectedConnector.getAddress());
restcommAddress = addr.getCanonicalHostName();
} catch (UnknownHostException e) {
logger.error("Unable to resolveWithBase: " + selectedConnector + " to hostname: " + e);
restcommAddress = selectedConnector.getAddress();
}
}
} else {
restcommAddress = selectedConnector.getAddress();
}
} else {
restcommAddress = selectedConnector.getAddress();
}

//TODO Resolve based on Organization domain name
String base = selectedConnector.getScheme() + "://" + restcommAddress + ":" + selectedConnector.getPort();
try {
return resolve(new URI(base), uri);
return resolveWithBase(new URI(base), uri);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Badly formed URI: " + base, e);
}
Expand All @@ -141,7 +160,7 @@ public static URI resolve(final URI uri) {
* @return The selected connector with Secure preference.
* @throws RuntimeException if no connector is found for some reason
*/
public static HttpConnector getHttpConnector() throws RuntimeException {
public HttpConnector getHttpConnector() throws RuntimeException {
if (selectedConnector == null) {
try {

Expand Down

0 comments on commit ec20791

Please sign in to comment.