blob: 1c1fa867ef387f20a9743ff88fcb89ffddac53cb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013-2016 LAAS-CNRS (www.laas.fr)
* 7 Colonel Roche 31077 Toulouse - France
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Initial Contributors:
* Thierry Monteil : Project manager, technical co-manager
* Mahdi Ben Alaya : Technical co-manager
* Samir Medjiah : Technical co-manager
* Khalil Drira : Strategy expert
* Guillaume Garzone : Developer
* François Aïssaoui : Developer
*
* New contributors :
*******************************************************************************/
package org.eclipse.om2m.core.redirector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.om2m.commons.constants.CSEType;
import org.eclipse.om2m.commons.constants.Constants;
import org.eclipse.om2m.commons.constants.MimeMediaType;
import org.eclipse.om2m.commons.constants.Operation;
import org.eclipse.om2m.commons.constants.ResponseStatusCode;
import org.eclipse.om2m.commons.entities.AeEntity;
import org.eclipse.om2m.commons.entities.RemoteCSEEntity;
import org.eclipse.om2m.commons.exceptions.Om2mException;
import org.eclipse.om2m.commons.exceptions.ResourceNotFoundException;
import org.eclipse.om2m.commons.resource.RemoteCSE;
import org.eclipse.om2m.commons.resource.RequestPrimitive;
import org.eclipse.om2m.commons.resource.ResponsePrimitive;
import org.eclipse.om2m.core.comm.RestClient;
import org.eclipse.om2m.core.controller.AEController;
import org.eclipse.om2m.core.datamapper.DataMapperSelector;
import org.eclipse.om2m.core.interworking.IpeSelector;
import org.eclipse.om2m.core.persistence.PersistenceService;
import org.eclipse.om2m.persistence.service.DAO;
import org.eclipse.om2m.persistence.service.DBService;
import org.eclipse.om2m.persistence.service.DBTransaction;
/**
* Re-target the REST request to the Distant CSE registered in the
* {@link RemoteCSE} children.
*
*/
public class Redirector {
private static Log LOGGER = LogFactory.getLog(Redirector.class);
/**
* Re-targets a request to a Distant SCL registered in the sclCollection.
*
* @param requestIndication
* - The generic request to handle.
* @return The generic returned response.
*/
public static ResponsePrimitive retarget(RequestPrimitive request) {
String remoteCseId = "";
ResponsePrimitive response = new ResponsePrimitive(request);
try {
remoteCseId = "/" + request.getTargetId().split("/")[1];
} catch (ArrayIndexOutOfBoundsException e) {
LOGGER.debug("Remote cse not found", e);
throw new ResourceNotFoundException("Remote cse not found", e);
}
// get the database service
DBService dbs = PersistenceService.getInstance().getDbService();
DBTransaction transaction = dbs.getDbTransaction();
transaction.open();
// get the dao of the parent
DAO<RemoteCSEEntity> dao = dbs.getDAOFactory().getRemoteCSEbyCseIdDAO();
RemoteCSEEntity csrEntity = dao.find(transaction, remoteCseId);
if (csrEntity != null) {
LOGGER.info("RemoteCSE found: " + csrEntity.getRemoteCseId());
response = sendRedirectorRequest(request, csrEntity, transaction);
} else {
if (!Constants.CSE_TYPE.equalsIgnoreCase(CSEType.IN)) {
LOGGER.info("Unknow CSE, sending request to registrar CSE: " + Constants.REMOTE_CSE_ID);
csrEntity = dao.find(transaction, "/" + Constants.REMOTE_CSE_ID);
if (csrEntity != null) {
// transfer the request and get the response
response = sendRedirectorRequest(request, csrEntity, transaction);
}
}
if (response == null) {
// case nothing found
throw new ResourceNotFoundException("RemoteCse with cseId " + remoteCseId + " has not been found");
}
}
transaction.close();
return response;
}
private static ResponsePrimitive sendRedirectorRequest(RequestPrimitive request, RemoteCSEEntity csrEntity,
DBTransaction transaction) {
// test if the remoteCse is reachable
if (!csrEntity.isRequestReachability()) {
throw new Om2mException("Remote Cse is not request reachable", ResponseStatusCode.TARGET_NOT_REACHABLE);
}
DBService dbs = PersistenceService.getInstance().getDbService();
// get Point of Access
String url = "";
if (!csrEntity.getPointOfAccess().isEmpty()) {
boolean done = false;
int i = 0;
// iterating on points of access while target are not reachable
while (!done & i < csrEntity.getPointOfAccess().size()) {
url = csrEntity.getPointOfAccess().get(i);
// Remove a potential / added at the end of the poa
if (url.endsWith("/")) {
LOGGER.debug("Removing / at the end of poa: " + url);
url = url.substring(0, url.length() - 1);
}
if (request.getTo().startsWith("//")) {
url += request.getTo().replaceFirst("//", "/_/");
} else if (request.getTo().startsWith("/")) {
url += request.getTo().replaceFirst("/", "/~/");
} else {
url += "/" + request.getTo();
}
request.setTo(url);
// modify the request if content type is OBJ.
String initialRequestContentType = request.getRequestContentType();
String initialReturnContentType = request.getReturnContentType();
if ((MimeMediaType.OBJ.equals(initialRequestContentType))) {
// forward payload using XML
request.setRequestContentType(MimeMediaType.XML);
if ((Operation.CREATE.equals(request.getOperation()))
|| (Operation.UPDATE.equals(request.getOperation()))) {
// convert content type as XML payload
String xmlPayload = DataMapperSelector.getDataMapperList().get(MimeMediaType.XML)
.objToString(request.getContent());
request.setContent(xmlPayload);
}
}
// if returnType=OBJ, change it to XML
if ((MimeMediaType.OBJ.equals(initialReturnContentType))) {
request.setReturnContentType(MimeMediaType.XML);
}
ResponsePrimitive response = RestClient.sendRequest(request);
if (!(response.getResponseStatusCode().equals(ResponseStatusCode.TARGET_NOT_REACHABLE))) {
done = true;
if (i > 0) {
String poa = csrEntity.getPointOfAccess().get(i);
csrEntity.getPointOfAccess().remove(i);
csrEntity.getPointOfAccess().add(0, poa);
dbs.getDAOFactory().getRemoteCSEDAO().update(transaction, csrEntity);
transaction.commit();
}
// convert response as expected
if (response.getContent() != null) {
if (MimeMediaType.OBJ.equals(initialReturnContentType)) {
Object resource = DataMapperSelector.getDataMapperList().get(MimeMediaType.XML)
.stringToObj((String) response.getContent());
response.setContent(resource);
}
}
return response;
}
i++;
}
// if we reach this point, there is no poa working
ResponsePrimitive response = new ResponsePrimitive(request);
response.setResponseStatusCode(ResponseStatusCode.TARGET_NOT_REACHABLE);
response.setContent("Target is not reachable");
response.setContentType(MimeMediaType.TEXT_PLAIN);
return response;
} else {
// TODO to improve w/ polling channel policy
throw new Om2mException("The point of access parameter is missing",
ResponseStatusCode.TARGET_NOT_REACHABLE);
}
}
public static ResponsePrimitive retargetNotify(RequestPrimitive request) {
ResponsePrimitive response = new ResponsePrimitive(request);
DBService dbs = PersistenceService.getInstance().getDbService();
DBTransaction dbt = dbs.getDbTransaction();
dbt.open();
// get the AE
AeEntity ae = dbs.getDAOFactory().getAeDAO().find(dbt, request.getTargetId());
if (ae == null) {
dbt.close();
throw new ResourceNotFoundException("AE resource " + request.getTargetId() + " not found.");
}
// FIXME use the correct originator when a notification is generated
if (!request.getFrom().equals("/" + Constants.CSE_ID)) {
new AEController().checkACP(ae.getAccessControlPolicies(), request.getFrom(), Operation.NOTIFY);
}
// Get point of access
if (ae.getPointOfAccess().isEmpty() || !(ae.isRequestReachability())) {
throw new Om2mException("AE has no point of access", ResponseStatusCode.TARGET_NOT_REACHABLE);
} else {
boolean done = false;
int i = 0;
// for each PoA
while (!done && (i < ae.getPointOfAccess().size())) {
String poa = ae.getPointOfAccess().get(i);
// if the PoA is a local IPE
if (IpeSelector.getInterworkingList().containsKey(poa)) {
try {
LOGGER.info("Sending notification to IPE: " + poa);
response = IpeSelector.getInterworkingList().get(poa).doExecute(request);
} catch (Om2mException om2mE) {
LOGGER.info("Om2m exception caught in Redirector: " + om2mE.getMessage());
throw om2mE;
} catch (Exception e) {
LOGGER.error("Exception caught in IPE execution", e);
throw new Om2mException("IPE Internal Error", e, ResponseStatusCode.INTERNAL_SERVER_ERROR);
}
done = true;
} else {
request.setTo(poa);
response = RestClient.sendRequest(request);
if (!response.getResponseStatusCode().equals(ResponseStatusCode.TARGET_NOT_REACHABLE)) {
done = true;
if (i > 0) {
ae.getPointOfAccess().remove(i);
ae.getPointOfAccess().add(0, poa);
dbs.getDAOFactory().getAeDAO().update(dbt, ae);
dbt.commit();
}
}
}
i++;
}
}
dbt.close();
return response;
}
}