| /******************************************************************************* |
| * Copyright (c) 2013-2020 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 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * 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; |
| |
| import java.math.BigInteger; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ScheduledExecutorService; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.eclipse.om2m.commons.constants.AccessControl; |
| 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.ResourceType; |
| import org.eclipse.om2m.commons.constants.ResponseStatusCode; |
| import org.eclipse.om2m.commons.constants.ResultContent; |
| import org.eclipse.om2m.commons.constants.ShortName; |
| import org.eclipse.om2m.commons.entities.AccessControlOriginatorEntity; |
| import org.eclipse.om2m.commons.entities.AccessControlPolicyEntity; |
| import org.eclipse.om2m.commons.entities.AccessControlRuleEntity; |
| import org.eclipse.om2m.commons.entities.CSEBaseEntity; |
| import org.eclipse.om2m.commons.entities.RemoteCSEEntity; |
| import org.eclipse.om2m.commons.resource.AccessControlPolicy; |
| 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.commons.utils.Util.DateUtil; |
| import org.eclipse.om2m.core.comm.RestClient; |
| import org.eclipse.om2m.core.controller.Controller; |
| import org.eclipse.om2m.core.datamapper.DataMapperSelector; |
| import org.eclipse.om2m.core.persistence.PersistenceService; |
| import org.eclipse.om2m.core.remotecse.RemoteCseService; |
| import org.eclipse.om2m.core.urimapper.UriMapper; |
| import org.eclipse.om2m.persistence.service.DBService; |
| import org.eclipse.om2m.persistence.service.DBTransaction; |
| |
| /** |
| * Initializer for CSE entity |
| * |
| */ |
| public class CSEInitializer implements Constants { |
| |
| /** Logger */ |
| private static final Log LOGGER = LogFactory.getLog(CSEInitializer.class); |
| |
| private static RemoteCSE currentRegistrationToIn; |
| |
| private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); |
| |
| private static final Object MUTEX = new Object(); |
| |
| /** Private constructor */ |
| private CSEInitializer() { |
| } |
| |
| private static String acpAdminId; |
| |
| /** |
| * Initialize the current launching CSE. |
| */ |
| public static void init() throws InterruptedException { |
| LOGGER.info("Initializating the cseBase"); |
| // Check the existence of the cseBase in the database |
| DBService dbs = PersistenceService.getInstance().getDbService(); |
| DBTransaction transaction = dbs.getDbTransaction(); |
| transaction.open(); |
| CSEBaseEntity cseBase = dbs.getDAOFactory().getCSEBaseDAO().find(transaction, "/" + Constants.CSE_ID); |
| // if the cseBase is not initialized, then create the base resources |
| if (cseBase == null) { |
| // Create AccessRight resource |
| LOGGER.info("Create AccessControlPolicy resource"); |
| initACP(); |
| |
| // Create CSEBase resource |
| LOGGER.info("Create CSEBase resource"); |
| initCSEBase(); |
| |
| if (!Constants.CSE_TYPE.equalsIgnoreCase(CSEType.IN) && Constants.CSE_AUTHENTICATION) { |
| LOGGER.info("Register CSE to another CSE."); |
| new Thread(new Runnable() { |
| |
| @Override |
| public void run() { |
| registerCSE(); |
| |
| checkPeriodicallyCSERegistration(); |
| } |
| }).start(); |
| } |
| } else { |
| LOGGER.info("cseBase already initialized"); |
| } |
| |
| } |
| |
| /** |
| * Creates the root {@link CseBase} resource in DataBase. |
| */ |
| private static void initCSEBase() { |
| CSEBaseEntity cseBaseEntity = new CSEBaseEntity(); |
| DBService db = PersistenceService.getInstance().getDbService(); |
| DBTransaction transaction = db.getDbTransaction(); |
| transaction.open(); |
| AccessControlPolicyEntity acpEntity = db.getDAOFactory().getAccessControlPolicyDAO().find(transaction, acpAdminId); |
| cseBaseEntity.getAccessControlPolicies().add(acpEntity); |
| cseBaseEntity.getChildAccessControlPolicies().add(acpEntity); |
| cseBaseEntity.setCreationTime(DateUtil.now()); |
| cseBaseEntity.setCseid(Constants.CSE_ID); |
| cseBaseEntity.setCseType(CSEType.toBigInteger(Constants.CSE_TYPE)); |
| cseBaseEntity.setLastModifiedTime(DateUtil.now()); |
| cseBaseEntity.setName(Constants.CSE_NAME); |
| cseBaseEntity.setResourceID("/" + Constants.CSE_ID); |
| cseBaseEntity.setResourceType(BigInteger.valueOf(ResourceType.CSE_BASE)); |
| cseBaseEntity.setHierarchicalURI("/" + Constants.CSE_ID + "/" + Constants.CSE_NAME); |
| // generating array of supported resources types |
| int[] supportedResources = { ResourceType.ACCESS_CONTROL_POLICY, ResourceType.AE, ResourceType.CONTAINER, |
| ResourceType.CONTENT_INSTANCE, ResourceType.CSE_BASE, ResourceType.GROUP, ResourceType.NODE, |
| ResourceType.POLLING_CHANNEL, ResourceType.REMOTE_CSE, ResourceType.REQUEST, |
| ResourceType.SUBSCRIPTION, ResourceType.FLEXCONTAINER }; |
| |
| for (int rt : supportedResources) { |
| cseBaseEntity.getSupportedResourceType().add(BigInteger.valueOf(rt)); |
| } |
| |
| cseBaseEntity.getPointOfAccess() |
| .add("http://" + Constants.CSE_IP + ":" + Constants.CSE_PORT + Constants.CSE_CONTEXT); |
| |
| UriMapper.addNewUri(cseBaseEntity.getHierarchicalURI(), cseBaseEntity.getResourceID(), ResourceType.CSE_BASE); |
| if (db.getDAOFactory().getCSEBaseDAO().find(transaction, cseBaseEntity.getResourceID()) == null) { |
| db.getDAOFactory().getCSEBaseDAO().create(transaction, cseBaseEntity); |
| } else { |
| db.getDAOFactory().getCSEBaseDAO().update(transaction, cseBaseEntity); |
| } |
| |
| // update acp admin entity's parent |
| CSEBaseEntity dbCseBaseEntity = db.getDAOFactory().getCSEBaseDAO().find(transaction, cseBaseEntity.getResourceID()); |
| acpEntity.setParentCse(dbCseBaseEntity); |
| |
| transaction.commit(); |
| transaction.close(); |
| } |
| |
| /** |
| * Sends {@link CseBase} resource in DataBase. |
| */ |
| private static void registerCSE() { |
| |
| String contentFormat = System.getProperty("org.eclipse.om2m.registration.contentFormat", MimeMediaType.XML); |
| |
| RemoteCSE remoteCSE = new RemoteCSE(); |
| switch (Constants.CSE_TYPE.toLowerCase()) { |
| case CSEType.ASN: |
| remoteCSE.setCseType(CSEType.ASN_CSE); |
| break; |
| case CSEType.MN: |
| remoteCSE.setCseType(CSEType.MN_CSE); |
| break; |
| default: |
| break; |
| } |
| String httpPoa = "http://" + Constants.CSE_IP + ":" + Constants.CSE_PORT + Constants.CSE_CONTEXT; |
| if (Constants.CSE_CONTEXT.length() > 1) { |
| httpPoa += "/"; |
| } |
| remoteCSE.getPointOfAccess().add(httpPoa); |
| remoteCSE.setCSEID("/" + Constants.CSE_ID); |
| remoteCSE.setCSEBase("//" + Constants.M2M_SP_ID + remoteCSE.getCSEID()); |
| remoteCSE.setRequestReachability(new Boolean(true)); |
| remoteCSE.setName(Constants.CSE_NAME); |
| |
| String representation = DataMapperSelector.getDataMapperList().get(contentFormat).objToString(remoteCSE); |
| |
| RequestPrimitive request = new RequestPrimitive(); |
| request.setFrom(Constants.ADMIN_REQUESTING_ENTITY); |
| String remotePoa = "http://" + Constants.REMOTE_CSE_IP + ":" + Constants.REMOTE_CSE_PORT + "/~" |
| + Constants.REMOTE_CSE_CONTEXT; |
| if (Constants.REMOTE_CSE_CONTEXT.length() > 1 && !Constants.REMOTE_CSE_CONTEXT.equals("/~")) { |
| remotePoa += "/"; |
| } |
| remotePoa += Constants.REMOTE_CSE_ID; |
| request.setTo(remotePoa); |
| request.setContent(representation); |
| request.setOperation(Operation.CREATE); |
| request.setResourceType(BigInteger.valueOf(ResourceType.REMOTE_CSE)); |
| request.setRequestContentType(contentFormat); |
| request.setRequestIdentifier("001"); |
| |
| boolean registered = false; |
| while (!registered) { |
| ResponsePrimitive response = RestClient.sendRequest(request); |
| LOGGER.info("response after registration: " + response); |
| if (response.getResponseStatusCode().equals(ResponseStatusCode.CREATED)) { |
| registered = true; |
| |
| // retrieve RemoteCSE entity and store it |
| synchronized (MUTEX) { |
| currentRegistrationToIn = (RemoteCSE) DataMapperSelector.getDataMapperList().get(contentFormat) |
| .stringToObj((String) response.getContent()); |
| } |
| |
| break; |
| } else if (ResponseStatusCode.CONFLICT.equals(response.getResponseStatusCode())) { |
| // conflict ==> the CSE was previously registered |
| // need to delete old registration |
| deleteRegistration(); |
| |
| // then create a new one |
| registered = false; |
| |
| } else { |
| try { |
| LOGGER.info("Error in registration to another CSE. Retrying in 10s"); |
| Thread.sleep(10000); |
| } catch (InterruptedException e) { |
| LOGGER.debug("Interrupted Exception", e); |
| } |
| } |
| } |
| LOGGER.info("Successfully registered to " + Constants.REMOTE_CSE_ID); |
| RemoteCSEEntity remoteCseEntity = new RemoteCSEEntity(); |
| remoteCseEntity.setCreationTime(DateUtil.now()); |
| remoteCseEntity.setLastModifiedTime(DateUtil.now()); |
| remoteCseEntity.setParentID("/" + Constants.CSE_ID); |
| |
| DBService dbs = PersistenceService.getInstance().getDbService(); |
| DBTransaction transaction = dbs.getDbTransaction(); |
| transaction.open(); |
| remoteCseEntity.getAccessControlPolicies() |
| .add(dbs.getDAOFactory().getAccessControlPolicyDAO().find(transaction, acpAdminId)); |
| remoteCseEntity.setResourceType(BigInteger.valueOf(ResourceType.REMOTE_CSE)); |
| remoteCseEntity.setHierarchicalURI( |
| "/" + Constants.CSE_ID + "/" + Constants.CSE_NAME + "/" + Constants.REMOTE_CSE_NAME); |
| String generatedId = Controller.generateId("", ""); |
| remoteCseEntity.setResourceID( |
| "/" + Constants.CSE_ID + "/" + ShortName.REMOTE_CSE + Constants.PREFIX_SEPERATOR + generatedId); |
| remoteCseEntity.setName(Constants.REMOTE_CSE_NAME); |
| UriMapper.addNewUri(remoteCseEntity.getHierarchicalURI(), remoteCseEntity.getResourceID(), |
| ResourceType.REMOTE_CSE); |
| remoteCseEntity.setRemoteCseId("/" + Constants.REMOTE_CSE_ID); |
| remoteCseEntity.setRemoteCseUri("//" + Constants.M2M_SP_ID + remoteCseEntity.getRemoteCseId()); |
| String poa = "http://" + Constants.REMOTE_CSE_IP + ":" + Constants.REMOTE_CSE_PORT |
| + Constants.REMOTE_CSE_CONTEXT; |
| if (Constants.REMOTE_CSE_CONTEXT.length() > 1) { |
| poa += "/"; |
| } |
| remoteCseEntity.getPointOfAccess().add(poa); |
| remoteCseEntity.setRequestReachability(true); |
| CSEBaseEntity cseBase = dbs.getDAOFactory().getCSEBaseDAO().find(transaction, "/" + Constants.CSE_ID); |
| cseBase.getRemoteCses().add(remoteCseEntity); |
| dbs.getDAOFactory().getCSEBaseDAO().update(transaction, cseBase); |
| dbs.getDAOFactory().getRemoteCSEDAO().create(transaction, remoteCseEntity); |
| transaction.commit(); |
| transaction.close(); |
| |
| RemoteCseService.getInstance().addRemoteCseAndPublish(remoteCseEntity); |
| } |
| |
| private static void deleteRegistration() { |
| |
| // send DELETE request the Registrar CSE |
| unregisterCse(); |
| |
| synchronized (MUTEX) { |
| currentRegistrationToIn = null; |
| } |
| |
| // make sure no remoteCse in database |
| DBService dbs = PersistenceService.getInstance().getDbService(); |
| DBTransaction transaction = dbs.getDbTransaction(); |
| transaction.open(); |
| RemoteCSEEntity remoteCse = dbs.getDAOFactory().getRemoteCSEbyCseIdDAO().find(transaction, |
| "/" + Constants.REMOTE_CSE_ID); |
| if (remoteCse != null) { |
| // remove RemoteCSE from database |
| dbs.getDAOFactory().getRemoteCSEDAO().delete(transaction, remoteCse); |
| UriMapper.deleteUri("/" + Constants.CSE_ID + "/" + Constants.CSE_NAME + "/" + Constants.REMOTE_CSE_NAME); |
| |
| LOGGER.info("remove remoteCSE from database"); |
| |
| // notify RemoteCseService |
| RemoteCseService.getInstance().removeRemoteCseAndPublish(remoteCse.getName()); |
| } else { |
| LOGGER.warn("No remoteCSE to remove from database"); |
| } |
| transaction.commit(); |
| transaction.close(); |
| |
| } |
| |
| /** |
| * Creates a default {@link AccessControlPolicy} resource in DataBase. |
| */ |
| private static void initACP() { |
| AccessControlPolicyEntity acp = new AccessControlPolicyEntity(); |
| acp.setParentID("/" + Constants.CSE_ID); |
| acp.setCreationTime(DateUtil.now()); |
| acp.setLastModifiedTime(DateUtil.now()); |
| acp.setResourceID( |
| "/" + Constants.CSE_ID + "/" + ShortName.ACP + Constants.PREFIX_SEPERATOR + Controller.generateId()); |
| acp.setName(Constants.ADMIN_PROFILE_ID); |
| acp.setResourceType(BigInteger.valueOf(ResourceType.ACCESS_CONTROL_POLICY)); |
| acp.setHierarchicalURI("/" + Constants.CSE_ID + "/" + Constants.CSE_NAME + "/" + acp.getName()); |
| acp.setResourceType(ResourceType.ACCESS_CONTROL_POLICY); |
| UriMapper.addNewUri(acp.getHierarchicalURI(), acp.getResourceID(), ResourceType.ACCESS_CONTROL_POLICY); |
| |
| // Self-privileges - all rights for admin |
| AccessControlRuleEntity ruleEntity = new AccessControlRuleEntity(); |
| AccessControlOriginatorEntity originatorEntity = new AccessControlOriginatorEntity( |
| Constants.ADMIN_REQUESTING_ENTITY); |
| ruleEntity.getAccessControlOriginators().add(originatorEntity); |
| ruleEntity.setCreate(true); |
| ruleEntity.setRetrieve(true); |
| ruleEntity.setUpdate(true); |
| ruleEntity.setDelete(true); |
| ruleEntity.setNotify(true); |
| ruleEntity.setDiscovery(true); |
| acp.getSelfPrivileges().add(ruleEntity); |
| |
| // Privileges - all rights for admin |
| ruleEntity = new AccessControlRuleEntity(); |
| ruleEntity.setCreate(true); |
| ruleEntity.setRetrieve(true); |
| ruleEntity.setUpdate(true); |
| ruleEntity.setDelete(true); |
| ruleEntity.setNotify(true); |
| ruleEntity.setDiscovery(true); |
| ruleEntity.getAccessControlOriginators() |
| .add(new AccessControlOriginatorEntity(Constants.ADMIN_REQUESTING_ENTITY)); |
| ruleEntity.getAccessControlOriginators().add(new AccessControlOriginatorEntity("/" + Constants.CSE_ID)); |
| acp.getPrivileges().add(ruleEntity); |
| |
| // privileges for ALL originators (read + discovery) |
| ruleEntity = new AccessControlRuleEntity(); |
| ruleEntity.setRetrieve(true); |
| ruleEntity.setDiscovery(true); |
| ruleEntity.getAccessControlOriginators() |
| .add(new AccessControlOriginatorEntity(Constants.GUEST_REQUESTING_ENTITY)); |
| acp.getPrivileges().add(ruleEntity); |
| |
| acpAdminId = acp.getResourceID(); |
| |
| DBService db = PersistenceService.getInstance().getDbService(); |
| DBTransaction transaction = db.getDbTransaction(); |
| transaction.open(); |
| if (db.getDAOFactory().getAccessControlPolicyDAO().find(transaction, acp.getResourceID()) == null) { |
| db.getDAOFactory().getAccessControlPolicyDAO().create(transaction, acp); |
| } else { |
| db.getDAOFactory().getAccessControlPolicyDAO().update(transaction, acp); |
| } |
| transaction.commit(); |
| transaction.close(); |
| } |
| |
| public static void unregisterCse() { |
| RequestPrimitive request = new RequestPrimitive(); |
| request.setFrom(Constants.ADMIN_REQUESTING_ENTITY); |
| request.setOperation(Operation.DELETE); |
| ; |
| String remotePoa = "http://" + Constants.REMOTE_CSE_IP + ":" + Constants.REMOTE_CSE_PORT + "/~"; |
| ; |
| if (Constants.REMOTE_CSE_CONTEXT.length() > 1) { |
| remotePoa += "/" + Constants.REMOTE_CSE_CONTEXT; |
| } |
| remotePoa += "/" + REMOTE_CSE_ID + "/" + REMOTE_CSE_NAME + "/" + CSE_NAME; |
| request.setTo(remotePoa); |
| request.setResultContent(ResultContent.NOTHING); |
| LOGGER.info("Sending unregistration request"); |
| ResponsePrimitive response = RestClient.sendRequest(request); |
| LOGGER.info("Unregistration response:\n" + response); |
| } |
| |
| private static void checkPeriodicallyCSERegistration() { |
| scheduler.scheduleWithFixedDelay(new Runnable() { |
| |
| @Override |
| public void run() { |
| LOGGER.info("check CSE registration"); |
| |
| RemoteCSE registration = null; |
| synchronized (MUTEX) { |
| registration = currentRegistrationToIn; |
| } |
| |
| if (registration != null) { |
| RemoteCSE remoteCSEFromIN = retrieveCSERegistration(); |
| |
| if (!compareRemoteCSE(registration, remoteCSEFromIN)) { |
| |
| // relaunch registration procedure |
| deleteRegistration(); |
| |
| registerCSE(); |
| } else { |
| LOGGER.info("registration is good"); |
| } |
| } else { |
| LOGGER.info("registration is null --> registration process on going"); |
| } |
| |
| } |
| }, 3, 3, TimeUnit.MINUTES); |
| |
| } |
| |
| protected static boolean compareRemoteCSE(RemoteCSE registration, RemoteCSE remoteCSEFromIN) { |
| if (remoteCSEFromIN == null) { |
| LOGGER.info("compareRemoteCSE() - remoteCSEFromIN is null"); |
| return false; |
| } |
| |
| // check only resource id |
| if (!remoteCSEFromIN.getResourceID().equals(registration.getResourceID())) { |
| LOGGER.info("compareRemoteCSE() - remoteCSEFromIN.resourceID(" + remoteCSEFromIN.getResourceID() |
| + ")!=registration.resourceID(" + registration.getResourceID() + ")"); |
| return false; |
| } |
| return true; |
| } |
| |
| protected static RemoteCSE retrieveCSERegistration() { |
| String contentFormat = System.getProperty("org.eclipse.om2m.registration.contentFormat", MimeMediaType.XML); |
| |
| try { |
| |
| RequestPrimitive request = new RequestPrimitive(); |
| request.setFrom(Constants.ADMIN_REQUESTING_ENTITY); |
| request.setOperation(Operation.RETRIEVE); |
| ; |
| String remotePoa = "http://" + Constants.REMOTE_CSE_IP + ":" + Constants.REMOTE_CSE_PORT + "/~"; |
| ; |
| if (Constants.REMOTE_CSE_CONTEXT.length() > 1) { |
| remotePoa += "/" + Constants.REMOTE_CSE_CONTEXT; |
| } |
| remotePoa += "/" + Constants.REMOTE_CSE_ID + "/" + Constants.REMOTE_CSE_NAME + "/" + Constants.CSE_NAME; |
| request.setTo(remotePoa); |
| request.setResultContent(ResultContent.ATTRIBUTES); |
| request.setReturnContentType(contentFormat); |
| ResponsePrimitive response = RestClient.sendRequest(request); |
| if (ResponseStatusCode.OK.equals(response.getResponseStatusCode())) { |
| return (RemoteCSE) DataMapperSelector.getDataMapperList().get(contentFormat) |
| .stringToObj((String) response.getContent()); |
| } |
| return null; |
| |
| } catch (Exception e) { |
| e.printStackTrace(); |
| return null; |
| } |
| } |
| |
| } |