Merge branch 'dev'
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..11ecb79
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,198 @@
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation
+ distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+ i) changes to the Program, and
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are
+ distributed by that particular Contributor. A Contribution 'originates' from
+ a Contributor if it was added to the Program by such Contributor itself or
+ anyone acting on such Contributor's behalf. Contributions do not include
+ additions to the Program which: (i) are separate modules of software
+ distributed in conjunction with the Program under their own license
+ agreement, and (ii) are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free copyright license to
+ reproduce, prepare derivative works of, publicly display, publicly perform,
+ distribute and sublicense the Contribution of such Contributor, if any, and
+ such derivative works, in source code and object code form.
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free patent license under
+ Licensed Patents to make, use, sell, offer to sell, import and otherwise
+ transfer the Contribution of such Contributor, if any, in source code and
+ object code form. This patent license shall apply to the combination of the
+ Contribution and the Program if, at the time the Contribution is added by
+ the Contributor, such addition of the Contribution causes such combination
+ to be covered by the Licensed Patents. The patent license shall not apply
+ to any other combinations which include the Contribution. No hardware per
+ se is licensed hereunder.
+ c) Recipient understands that although each Contributor grants the licenses to
+ its Contributions set forth herein, no assurances are provided by any
+ Contributor that the Program does not infringe the patent or other
+ intellectual property rights of any other entity. Each Contributor
+ disclaims any liability to Recipient for claims brought by any other entity
+ based on infringement of intellectual property rights or otherwise. As a
+ condition to exercising the rights and licenses granted hereunder, each
+ Recipient hereby assumes sole responsibility to secure any other
+ intellectual property rights needed, if any. For example, if a third party
+ patent license is required to allow Recipient to distribute the Program, it
+ is Recipient's responsibility to acquire that license before distributing
+ the Program.
+ d) Each Contributor represents that to its knowledge it has sufficient
+ copyright rights in its Contribution, if any, to grant the copyright
+ license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its
+own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+ b) its license agreement:
+ i) effectively disclaims on behalf of all Contributors all warranties and
+ conditions, express and implied, including warranties or conditions of
+ title and non-infringement, and implied warranties or conditions of
+ merchantability and fitness for a particular purpose;
+ ii) effectively excludes on behalf of all Contributors all liability for
+ damages, including direct, indirect, special, incidental and
+ consequential damages, such as lost profits;
+ iii) states that any provisions which differ from this Agreement are offered
+ by that Contributor alone and not by any other party; and
+ iv) states that source code for the Program is available from such
+ Contributor, and informs licensees how to obtain it in a reasonable
+ manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+ b) a copy of this Agreement must be included with each copy of the Program.
+ Contributors may not remove or alter any copyright notices contained within
+ the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if
+any, in a manner that reasonably allows subsequent Recipients to identify the
+originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a manner
+which does not create potential liability for other Contributors. Therefore, if
+a Contributor includes the Program in a commercial product offering, such
+Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any losses, damages
+and costs (collectively "Losses") arising from claims, lawsuits and other legal
+actions brought by a third party against the Indemnified Contributor to the
+extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor to
+control, and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may participate in
+any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If that
+Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such
+Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a court
+requires any other Contributor to pay any damages as a result, the Commercial
+Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+Recipient is solely responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its exercise of
+rights under this Agreement , including but not limited to the risks and costs
+of program errors, compliance with applicable laws, damage to or loss of data,
+programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable
+law, it shall not affect the validity or enforceability of the remainder of the
+terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such
+provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+(excluding combinations of the Program with other software or hardware)
+infringes such Recipient's patent(s), then such Recipient's rights granted under
+Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and does
+not cure such failure in a reasonable period of time after becoming aware of
+such noncompliance. If all Recipient's rights under this Agreement terminate,
+Recipient agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under this Agreement
+and any licenses granted by Recipient relating to the Program shall continue and
+survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to time.
+No one other than the Agreement Steward has the right to modify this Agreement.
+The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation
+may assign the responsibility to serve as the Agreement Steward to a suitable
+separate entity. Each new version of the Agreement will be given a
+distinguishing version number. The Program (including Contributions) may always
+be distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to distribute the Program (including its Contributions)
+under the new version. Except as expressly stated in Sections 2(a) and 2(b)
+above, Recipient receives no rights or licenses to the intellectual property of
+any Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted under
+this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial in
+any resulting litigation.
diff --git a/build.gradle b/build.gradle
index 27d74ee..0b08a36 100644
--- a/build.gradle
+++ b/build.gradle
@@ -50,6 +50,10 @@
}
}
+configurations {
+ all*.exclude group: 'javax.inject', module: 'javax.inject'
+}
+
dependencies {
compile 'javax:javaee-api:7.0'
@@ -67,13 +71,10 @@
compile 'com.google.protobuf:protobuf-java:3.0.0-beta-3'
compile 'com.google.protobuf:protobuf-java-util:3.0.0-beta-3'
compile 'com.google.guava:guava:18.0'
- compile 'org.glassfish.jersey.core:jersey-client:2.23.1'
- compile 'org.glassfish.jersey.media:jersey-media-sse:2.23.1'
+ compile 'org.glassfish.jersey.core:jersey-client:2.23.2'
+ compile 'org.glassfish.jersey.media:jersey-media-sse:2.23.2'
generatedCompile 'com.google.protobuf:protobuf-java:3.0.0-beta-3'
- // Avalon notification service
- compile 'org.jacorb:jacorb-services:3.8'
-
// querying es
compile 'commons-httpclient:commons-httpclient:3.1'
compile 'org.apache.commons:commons-lang3:3.4'
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
index 03874c1..d924057 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
@@ -12,9 +12,12 @@
import org.asam.ods.AoException;
import org.asam.ods.AoSession;
+import org.asam.ods.ElemId;
+import org.asam.ods.InstanceElement;
import org.eclipse.mdm.api.base.ConnectionException;
import org.eclipse.mdm.api.base.adapter.ModelManager;
import org.eclipse.mdm.api.base.file.FileService;
+import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.notification.NotificationService;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.base.query.QueryService;
@@ -27,9 +30,11 @@
import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
import org.eclipse.mdm.api.odsadapter.notification.ODSNotificationServiceFactory;
import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
import org.eclipse.mdm.api.odsadapter.query.ODSQueryService;
import org.eclipse.mdm.api.odsadapter.search.ODSSearchService;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
import org.omg.CORBA.ORB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -156,6 +161,15 @@
}
/**
+ * @returns the string "ods"
+ */
+ @Override
+ public String getAdapterType() {
+ return "ods";
+ }
+
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
index 3ec55f7..308e591 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
@@ -8,6 +8,7 @@
package org.eclipse.mdm.api.odsadapter;
+import java.util.HashMap;
import java.util.Map;
import org.asam.ods.AoException;
@@ -107,7 +108,12 @@
LOGGER.info("Connection to ODS server established.");
CORBAFileServerIF fileServer = serviceLocator.resolveFileServer(nameOfService);
- return new ODSContext(orb, aoSession, fileServer, parameters);
+
+ // Create a parameters map without password (which should not be visible from this point onwards),
+ // leaving the original map untouched:
+ Map<String, String> mapParams = new HashMap<>(parameters);
+ mapParams.remove(PARAM_PASSWORD);
+ return new ODSContext(orb, aoSession, fileServer, mapParams);
} catch (AoException e) {
closeSession(aoSession);
throw new ConnectionException("Unable to connect to ODS server due to: " + e.reason, e);
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
index 20fd266..8b5fbe0 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
@@ -12,6 +12,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -19,8 +20,9 @@
import java.util.stream.Collectors;
import org.asam.ods.AoException;
+import org.asam.ods.ApplicationStructure;
+import org.asam.ods.ElemId;
import org.asam.ods.InstanceElement;
-import org.eclipse.mdm.api.base.ConnectionException;
import org.eclipse.mdm.api.base.ServiceNotProvidedException;
import org.eclipse.mdm.api.base.Transaction;
import org.eclipse.mdm.api.base.adapter.EntityType;
@@ -45,6 +47,7 @@
import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
import org.eclipse.mdm.api.odsadapter.transaction.ODSTransaction;
import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
@@ -364,4 +367,57 @@
}
}
+ /**
+ * Retrives the ASAM paths for the given entities. The ASAM paths are prefixed with a servicename, in the form
+ * <code>corbaloc:[iop|ssliop]:1.2@HOSTNAME:PORT/NameService/MDM.ASAM-ODS/</code>
+ * @returns returns a map with the ASAM paths to the given entities. If a entity is not found in the ODS server
+ * the entity is not included in the result map.
+ * @throws DataAccessException if links could not be loaded for the given entities
+ * @throws IllegalArgumentException if a the source or typeName of an entity is invalid
+ * @see org.eclipse.mdm.api.base.BaseEntityManager#getLinks(Collection)
+ */
+ @Override
+ public Map<Entity, String> getLinks(Collection<Entity> entities) throws DataAccessException {
+
+ Map<Entity, String> linkMap = new HashMap<>();
+
+ ApplicationStructure appStructure;
+ try {
+ appStructure = odsModelManager.getAoSession().getApplicationStructure();
+ } catch (AoException e) {
+ throw new DataAccessException("Could not load application structure! Reason: " + e.reason, e);
+ }
+
+ String serverRoot = context.getParameters().get(ODSContextFactory.PARAM_NAMESERVICE)
+ + "/" + context.getParameters().get(ODSContextFactory.PARAM_SERVICENAME);
+
+ Map<String, List<Entity>> entitiesByTypeName = entities.stream()
+ .filter(e -> e.getTypeName() != null)
+ .collect(Collectors.groupingBy(Entity::getTypeName));
+
+ for (Map.Entry<String, List<Entity>> entry : entitiesByTypeName.entrySet()) {
+ ODSEntityType et = (ODSEntityType) odsModelManager.getEntityType(entry.getKey());
+
+ List<ElemId> elemIds = entry.getValue().stream()
+ .map(e -> new ElemId(et.getODSID(), ODSConverter.toODSLong(Long.parseLong(e.getID()))))
+ .collect(Collectors.toList());
+
+ try {
+ InstanceElement[] instances = appStructure.getInstancesById(elemIds.toArray(new ElemId[0]));
+
+ for (InstanceElement ie : instances) {
+ String id = Long.toString(ODSConverter.fromODSLong(ie.getId()));
+ String asamPath = serverRoot + ie.getAsamPath();
+ entry.getValue().stream()
+ .filter(e -> e.getID().equals(id))
+ .findFirst()
+ .ifPresent(e -> linkMap.put(e, asamPath));
+ }
+ } catch (AoException e) {
+ LOGGER.debug("Could not load links for entities: " + entities + ". Reason: " + e.reason, e);
+ }
+ }
+
+ return linkMap;
+ }
}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
index c7cdb3c..9ce663a 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
@@ -51,18 +51,10 @@
*/
final class CORBAFileServer {
- // ======================================================================
- // Class variables
- // ======================================================================
-
private static final Logger LOGGER = LoggerFactory.getLogger(CORBAFileServer.class);
private static final int DEFAULT_BUFFER_SIZE = 100_000;
private static final int SOCKET_TIMEOUT = 5_000;
- // ======================================================================
- // Instance variables
- // ======================================================================
-
private final CORBAFileServerIF fileServer;
private final AoSession aoSession;
private final ORB orb;
@@ -71,10 +63,6 @@
private final int bufferSize;
- // ======================================================================
- // Constructors
- // ======================================================================
-
/**
* Constructor.
*
@@ -96,11 +84,7 @@
bufferSize = getBufferSize();
}
-
- // ======================================================================
- // Public methods
- // ======================================================================
-
+
/**
* Opens a consumable download {@link InputStream} for given
* {@link FileLink}.
@@ -188,10 +172,6 @@
}
}
- // ======================================================================
- // Public methods
- // ======================================================================
-
/**
* Opens a simple {@link InputStreamIF} using the {@link CORBAFileServerIF}.
*
@@ -236,7 +216,7 @@
* registration is done asynchronously!
*/
fileServer.getForInstanceBySocket(aoSession, fileLink.getRemotePath(), elemId.aid, elemId.iid,
- InetAddress.getLocalHost().getHostName(), serverSocket.getLocalPort());
+ InetAddress.getLocalHost().getHostAddress(), serverSocket.getLocalPort());
} catch (CORBAFileServerException | IOException e) {
LOGGER.error("Unable to initialize socket stream, awaiting socket timeout.", e);
}
@@ -305,7 +285,7 @@
try {
return fileServer.saveForInstanceBySocket(aoSession, fileLink.getFileName(), "", elemId.aid, elemId.iid,
- InetAddress.getLocalHost().getHostName(), serverSocket.getLocalPort());
+ InetAddress.getLocalHost().getHostAddress(), serverSocket.getLocalPort());
} catch (CORBAFileServerException e) {
throw new IOException("Unable to upload file via socket due to: " + e.reason, e);
}
@@ -324,31 +304,19 @@
// try to use the same buffer size as the corba file server for best
// performance
return Integer.parseInt(fileServer.getContext(aoSession, "CORBAFileServer.BufferSize"));
- } catch (CORBAFileServerException e) {
+ } catch (NumberFormatException | CORBAFileServerException e) {
return DEFAULT_BUFFER_SIZE;
}
}
- // ======================================================================
- // Inner classes
- // ======================================================================
-
/**
* A simple {@link InputStream} adapter implementation for an
* {@link InputStreamIF}.
*/
private static final class InputStreamAdapter extends InputStream {
- // ======================================================================
- // Instance variables
- // ======================================================================
-
private final InputStreamIF inputStream;
- // ======================================================================
- // Constructors
- // ======================================================================
-
/**
* Constructor.
*
@@ -358,11 +326,7 @@
private InputStreamAdapter(InputStreamIF inputStream) {
this.inputStream = inputStream;
}
-
- // ======================================================================
- // Public methods
- // ======================================================================
-
+
/**
* {@inheritDoc}
*/
@@ -412,20 +376,12 @@
*/
private static final class CORBAInputStreamAdapter extends InputStreamIFPOA implements AutoCloseable {
- // ======================================================================
- // Instance variables
- // ======================================================================
-
private final InputStream inputStream;
private final long length;
private final byte[] objectID;
private final POA poa;
- // ======================================================================
- // Constructors
- // ======================================================================
-
/**
* Constructor.
*
@@ -452,10 +408,6 @@
}
}
- // ======================================================================
- // Public methods
- // ======================================================================
-
/**
* {@inheritDoc}
*/
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
index b48f46a..d032b59 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
@@ -119,7 +119,7 @@
EntityConfig<?> config = contextConfigs.get(entityType.getName());
if (config == null) {
- new IllegalArgumentException("Entity configuration for type '" + entityType + "' not found.");
+ throw new IllegalArgumentException("Entity configuration for type '" + entityType + "' not found.");
}
// config is either a context component or context sensor type
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
index 3f64d9b..57be20d 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
@@ -9,8 +9,6 @@
import org.eclipse.mdm.api.base.notification.NotificationService;
import org.eclipse.mdm.api.base.query.QueryService;
import org.eclipse.mdm.api.dflt.ApplicationContext;
-import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
-import org.eclipse.mdm.api.odsadapter.notification.avalon.AvalonNotificationManager;
import org.eclipse.mdm.api.odsadapter.notification.peak.PeakNotificationManager;
import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
import org.slf4j.Logger;
@@ -61,24 +59,25 @@
}
} else if (SERVER_TYPE_AVALON.equalsIgnoreCase(type)) {
- String serviceName = getParameter(parameters, ODSContextFactory.PARAM_SERVICENAME);
- serviceName = serviceName.replace(".ASAM-ODS", "");
- String nameServiceURL = getParameter(parameters, ODSContextFactory.PARAM_NAMESERVICE);
-
- LOGGER.info("Connecting to Avalon Notification Server ...");
- LOGGER.info("Name service URL: {}", nameServiceURL);
- LOGGER.info("Service name: {}", serviceName);
-
- long pollingInterval = 500L;
- try {
- pollingInterval = Long.parseLong(getParameter(parameters, PARAM_POLLING_INTERVAL));
- } catch (NumberFormatException | ConnectionException e) {
- LOGGER.warn("Could not parse parse parameter pollingInterval. Using default value: " + pollingInterval,
- e);
- }
-
- return new AvalonNotificationManager((ODSModelManager) mm, queryService, serviceName, nameServiceURL, true,
- pollingInterval);
+ throw new IllegalArgumentException("Avalon notification service is not supported yet.");
+// String serviceName = getParameter(parameters, ODSContextFactory.PARAM_SERVICENAME);
+// serviceName = serviceName.replace(".ASAM-ODS", "");
+// String nameServiceURL = getParameter(parameters, ODSContextFactory.PARAM_NAMESERVICE);
+//
+// LOGGER.info("Connecting to Avalon Notification Server ...");
+// LOGGER.info("Name service URL: {}", nameServiceURL);
+// LOGGER.info("Service name: {}", serviceName);
+//
+// long pollingInterval = 500L;
+// try {
+// pollingInterval = Long.parseLong(getParameter(parameters, PARAM_POLLING_INTERVAL));
+// } catch (NumberFormatException | ConnectionException e) {
+// LOGGER.warn("Could not parse parse parameter pollingInterval. Using default value: " + pollingInterval,
+// e);
+// }
+//
+// return new AvalonNotificationManager((ODSModelManager) mm, queryService, serviceName, nameServiceURL, true,
+// pollingInterval);
} else {
throw new ConnectionException("Invalid server type. Expected on of: 'peak'");
}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
index 6233afc..d30c966 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
@@ -1,182 +1,182 @@
-package org.eclipse.mdm.api.odsadapter.notification.avalon;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import org.asam.ods.T_LONGLONG;
-import org.eclipse.mdm.api.base.adapter.EntityType;
-import org.eclipse.mdm.api.base.model.ContextComponent;
-import org.eclipse.mdm.api.base.model.ContextDescribable;
-import org.eclipse.mdm.api.base.model.ContextRoot;
-import org.eclipse.mdm.api.base.model.User;
-import org.eclipse.mdm.api.base.notification.NotificationException;
-import org.eclipse.mdm.api.base.notification.NotificationFilter;
-import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
-import org.eclipse.mdm.api.base.notification.NotificationListener;
-import org.eclipse.mdm.api.base.notification.NotificationService;
-import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.QueryService;
-import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
-import org.eclipse.mdm.api.odsadapter.notification.NotificationEntityLoader;
-import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
-import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
-import org.omg.CORBA.ORB;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.highqsoft.avalonCorbaNotification.notification.MODE_DELETE;
-import com.highqsoft.avalonCorbaNotification.notification.MODE_INSERT;
-import com.highqsoft.avalonCorbaNotification.notification.MODE_MODIFYRIGHTS;
-import com.highqsoft.avalonCorbaNotification.notification.MODE_REPLACE;
-
-/**
- * Notification manager for handling notifications from the Avalon Notification
- * Service
- *
- * ModificationType.MODEL_MODIFIED is not supported!
- *
- * @since 1.0.0
- * @author Matthias Koller, Peak Solution GmbH
- *
- */
-public class AvalonNotificationManager implements NotificationService {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(AvalonNotificationManager.class);
-
- private final Map<String, EventProcessor> eventProcessors = new HashMap<>();
-
- private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
-
- private final ODSModelManager modelManager;
- private final String serviceName;
- private final String nameServiceURL;
- private long pollingInterval = 500L;
- private final NotificationEntityLoader loader;
-
- private final ORB orb = ORB.init(new String[] {}, System.getProperties());
-
- /**
- * Creates a new AvalonNotificationManager.
- *
- * @param modelManager
- * ODSModelManager used to laod entities.
- * @param serviceName
- * name of the notification service.
- * @param nameServiceURL
- * URL of the name service.
- * @param loadContextDescribable
- * if true, notifications for {@link ContextRoot} and
- * {@link ContextComponent} will load their parent
- * {@link ContextDescribable}.
- * @param pollingInterval
- * polling interval in milleseconds
- */
- public AvalonNotificationManager(ODSModelManager modelManager, QueryService queryService, String serviceName, String nameServiceURL,
- boolean loadContextDescribable, long pollingInterval) {
- this.modelManager = modelManager;
- this.serviceName = serviceName;
- this.nameServiceURL = nameServiceURL;
- this.pollingInterval = pollingInterval;
- loader = new NotificationEntityLoader(modelManager, queryService, loadContextDescribable);
- }
-
- @Override
- public void register(String registration, NotificationFilter filter, final NotificationListener listener)
- throws NotificationException {
- try {
- EventProcessor consumer = new EventProcessor(orb, listener, this, nameServiceURL, serviceName);
-
- List<String> aids = filter.getEntityTypes().stream().map(e -> e.getId()).collect(Collectors.toList());
-
- Set<ModificationType> modes = filter.getTypes().stream()
- .filter(m -> !ModificationType.MODEL_MODIFIED.equals(m)).collect(Collectors.toSet());
-
- consumer.connect();
- consumer.setFilter(aids, modes);
-
- ScheduledFuture<?> future = executor.scheduleAtFixedRate(consumer, 0, pollingInterval,
- TimeUnit.MILLISECONDS);
- consumer.setFuture(future);
-
- eventProcessors.put(registration, consumer);
- } catch (Exception e) {
- throw new NotificationException("Exception creating notification listener registration!", e);
- }
- }
-
- @Override
- public void deregister(String registration) {
- EventProcessor processor = eventProcessors.get(registration);
- if (processor != null) {
- processor.disconnect();
- eventProcessors.remove(registration);
- }
- }
-
- @Override
- public void close(boolean isDeregisterAll) throws NotificationException {
- LOGGER.info("Closing NotificationManager...");
-
- for (String registration : eventProcessors.keySet()) {
- LOGGER.debug("Disconnecting registration '" + registration + "'.");
- deregister(registration);
- }
-
- try {
- executor.shutdown();
- boolean terminated = executor.awaitTermination(10, TimeUnit.SECONDS);
- if (!terminated) {
- throw new NotificationException("Could not close all registrations!");
- }
- } catch (InterruptedException e) {
- throw new NotificationException("Could not close all registrations!", e);
- }
- }
-
- void processException(Exception e) {
- LOGGER.error("Exception during notification processing!", e);
- }
-
- void processNotification(short mode, T_LONGLONG aeId, T_LONGLONG ieId, T_LONGLONG userId, String timestamp,
- NotificationListener notificationListener) {
-
- try {
- User user = loader.load(new Key<>(User.class), Long.toString(ODSConverter.fromODSLong(userId)));
- LOGGER.debug("User loaded");
-
- EntityType entityType = modelManager.getEntityType(Long.toString(ODSConverter.fromODSLong(aeId)));
- List<String> ids = Arrays.asList(Long.toString(ODSConverter.fromODSLong(ieId)));
-
- if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("Notification event with: entityType=" + entityType + ", user=" + user);
- }
-
- switch (mode) {
- case MODE_INSERT.value:
- notificationListener.instanceCreated(loader.loadEntities(entityType, ids), user);
- break;
- case MODE_REPLACE.value:
- notificationListener.instanceModified(loader.loadEntities(entityType, ids), user);
- break;
- case MODE_DELETE.value:
- notificationListener.instanceDeleted(entityType, ids, user);
- break;
- case MODE_MODIFYRIGHTS.value:
- notificationListener.securityModified(entityType, ids, user);
- break;
- default:
- processException(new NotificationException("Invalid notification type!"));
- }
- } catch (DataAccessException e) {
- processException(new NotificationException("Cannot load data for notification!", e));
- }
- }
-}
+//package org.eclipse.mdm.api.odsadapter.notification.avalon;
+//
+//import java.util.Arrays;
+//import java.util.HashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.Executors;
+//import java.util.concurrent.ScheduledExecutorService;
+//import java.util.concurrent.ScheduledFuture;
+//import java.util.concurrent.TimeUnit;
+//import java.util.stream.Collectors;
+//
+//import org.asam.ods.T_LONGLONG;
+//import org.eclipse.mdm.api.base.adapter.EntityType;
+//import org.eclipse.mdm.api.base.model.ContextComponent;
+//import org.eclipse.mdm.api.base.model.ContextDescribable;
+//import org.eclipse.mdm.api.base.model.ContextRoot;
+//import org.eclipse.mdm.api.base.model.User;
+//import org.eclipse.mdm.api.base.notification.NotificationException;
+//import org.eclipse.mdm.api.base.notification.NotificationFilter;
+//import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
+//import org.eclipse.mdm.api.base.notification.NotificationListener;
+//import org.eclipse.mdm.api.base.notification.NotificationService;
+//import org.eclipse.mdm.api.base.query.DataAccessException;
+//import org.eclipse.mdm.api.base.query.QueryService;
+//import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+//import org.eclipse.mdm.api.odsadapter.notification.NotificationEntityLoader;
+//import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+//import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+//import org.omg.CORBA.ORB;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//
+//import com.highqsoft.avalonCorbaNotification.notification.MODE_DELETE;
+//import com.highqsoft.avalonCorbaNotification.notification.MODE_INSERT;
+//import com.highqsoft.avalonCorbaNotification.notification.MODE_MODIFYRIGHTS;
+//import com.highqsoft.avalonCorbaNotification.notification.MODE_REPLACE;
+//
+///**
+// * Notification manager for handling notifications from the Avalon Notification
+// * Service
+// *
+// * ModificationType.MODEL_MODIFIED is not supported!
+// *
+// * @since 1.0.0
+// * @author Matthias Koller, Peak Solution GmbH
+// *
+// */
+//public class AvalonNotificationManager implements NotificationService {
+//
+// private static final Logger LOGGER = LoggerFactory.getLogger(AvalonNotificationManager.class);
+//
+// private final Map<String, EventProcessor> eventProcessors = new HashMap<>();
+//
+// private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+//
+// private final ODSModelManager modelManager;
+// private final String serviceName;
+// private final String nameServiceURL;
+// private long pollingInterval = 500L;
+// private final NotificationEntityLoader loader;
+//
+// private final ORB orb = ORB.init(new String[] {}, System.getProperties());
+//
+// /**
+// * Creates a new AvalonNotificationManager.
+// *
+// * @param modelManager
+// * ODSModelManager used to laod entities.
+// * @param serviceName
+// * name of the notification service.
+// * @param nameServiceURL
+// * URL of the name service.
+// * @param loadContextDescribable
+// * if true, notifications for {@link ContextRoot} and
+// * {@link ContextComponent} will load their parent
+// * {@link ContextDescribable}.
+// * @param pollingInterval
+// * polling interval in milleseconds
+// */
+// public AvalonNotificationManager(ODSModelManager modelManager, QueryService queryService, String serviceName, String nameServiceURL,
+// boolean loadContextDescribable, long pollingInterval) {
+// this.modelManager = modelManager;
+// this.serviceName = serviceName;
+// this.nameServiceURL = nameServiceURL;
+// this.pollingInterval = pollingInterval;
+// loader = new NotificationEntityLoader(modelManager, queryService, loadContextDescribable);
+// }
+//
+// @Override
+// public void register(String registration, NotificationFilter filter, final NotificationListener listener)
+// throws NotificationException {
+// try {
+// EventProcessor consumer = new EventProcessor(orb, listener, this, nameServiceURL, serviceName);
+//
+// List<String> aids = filter.getEntityTypes().stream().map(e -> e.getId()).collect(Collectors.toList());
+//
+// Set<ModificationType> modes = filter.getTypes().stream()
+// .filter(m -> !ModificationType.MODEL_MODIFIED.equals(m)).collect(Collectors.toSet());
+//
+// consumer.connect();
+// consumer.setFilter(aids, modes);
+//
+// ScheduledFuture<?> future = executor.scheduleAtFixedRate(consumer, 0, pollingInterval,
+// TimeUnit.MILLISECONDS);
+// consumer.setFuture(future);
+//
+// eventProcessors.put(registration, consumer);
+// } catch (Exception e) {
+// throw new NotificationException("Exception creating notification listener registration!", e);
+// }
+// }
+//
+// @Override
+// public void deregister(String registration) {
+// EventProcessor processor = eventProcessors.get(registration);
+// if (processor != null) {
+// processor.disconnect();
+// eventProcessors.remove(registration);
+// }
+// }
+//
+// @Override
+// public void close(boolean isDeregisterAll) throws NotificationException {
+// LOGGER.info("Closing NotificationManager...");
+//
+// for (String registration : eventProcessors.keySet()) {
+// LOGGER.debug("Disconnecting registration '" + registration + "'.");
+// deregister(registration);
+// }
+//
+// try {
+// executor.shutdown();
+// boolean terminated = executor.awaitTermination(10, TimeUnit.SECONDS);
+// if (!terminated) {
+// throw new NotificationException("Could not close all registrations!");
+// }
+// } catch (InterruptedException e) {
+// throw new NotificationException("Could not close all registrations!", e);
+// }
+// }
+//
+// void processException(Exception e) {
+// LOGGER.error("Exception during notification processing!", e);
+// }
+//
+// void processNotification(short mode, T_LONGLONG aeId, T_LONGLONG ieId, T_LONGLONG userId, String timestamp,
+// NotificationListener notificationListener) {
+//
+// try {
+// User user = loader.load(new Key<>(User.class), Long.toString(ODSConverter.fromODSLong(userId)));
+// LOGGER.debug("User loaded");
+//
+// EntityType entityType = modelManager.getEntityTypeById(Long.toString(ODSConverter.fromODSLong(aeId)));
+// List<String> ids = Arrays.asList(Long.toString(ODSConverter.fromODSLong(ieId)));
+//
+// if (LOGGER.isTraceEnabled()) {
+// LOGGER.trace("Notification event with: entityType=" + entityType + ", user=" + user);
+// }
+//
+// switch (mode) {
+// case MODE_INSERT.value:
+// notificationListener.instanceCreated(loader.loadEntities(entityType, ids), user);
+// break;
+// case MODE_REPLACE.value:
+// notificationListener.instanceModified(loader.loadEntities(entityType, ids), user);
+// break;
+// case MODE_DELETE.value:
+// notificationListener.instanceDeleted(entityType, ids, user);
+// break;
+// case MODE_MODIFYRIGHTS.value:
+// notificationListener.securityModified(entityType, ids, user);
+// break;
+// default:
+// processException(new NotificationException("Invalid notification type!"));
+// }
+// } catch (DataAccessException e) {
+// processException(new NotificationException("Cannot load data for notification!", e));
+// }
+// }
+//}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java
index 05cdd92..32f5778 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java
@@ -1,270 +1,270 @@
-package org.eclipse.mdm.api.odsadapter.notification.avalon;
-
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ScheduledFuture;
-import java.util.stream.Collectors;
-
-import org.eclipse.mdm.api.base.notification.NotificationException;
-import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
-import org.eclipse.mdm.api.base.notification.NotificationListener;
-import org.omg.CORBA.ORB;
-import org.omg.CosNaming.NamingContextExt;
-import org.omg.CosNaming.NamingContextExtHelper;
-import org.omg.CosNotification.EventType;
-import org.omg.CosNotification.StructuredEvent;
-import org.omg.CosNotifyChannelAdmin.ClientType;
-import org.omg.CosNotifyChannelAdmin.EventChannel;
-import org.omg.CosNotifyChannelAdmin.EventChannelHelper;
-import org.omg.CosNotifyChannelAdmin.StructuredProxyPullSupplier;
-import org.omg.CosNotifyChannelAdmin.StructuredProxyPullSupplierHelper;
-import org.omg.CosNotifyComm.InvalidEventType;
-import org.omg.CosNotifyComm.StructuredPullConsumerPOA;
-import org.omg.CosNotifyFilter.ConstraintExp;
-import org.omg.CosNotifyFilter.Filter;
-import org.omg.CosNotifyFilter.FilterFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent;
-import com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper;
-
-/**
- * Event processor responsible for receiving avalon events from the notification
- * service and redirect them to the manager.
- *
- * @since 1.0.0
- * @author Matthias Koller, Peak Solution GmbH
- *
- */
-public class EventProcessor extends StructuredPullConsumerPOA implements Runnable {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(EventProcessor.class);
-
- private static final String eventDomainName = "AVALON";
-
- private final ORB orb;
- private final NotificationListener listener;
- private final AvalonNotificationManager manager;
- private final String nameserviceUrl;
- private final String serviceName;
-
- private EventChannel eventChannel;
- private StructuredProxyPullSupplier proxyPullSupplier;
-
- private boolean connected = false;
-
- private ScheduledFuture<?> future;
-
- /**
- * Creates a new event processor.
- *
- * @param orb
- * CORBA orb to use
- * @param listener
- * notification listener consuming the received events
- * @param manager
- * notification manager responsible for processing the events
- * @param serviceName
- * service name of the CORBA notification service
- */
- public EventProcessor(ORB orb, NotificationListener listener, AvalonNotificationManager manager,
- String nameserviceUrl, String serviceName) {
- this.orb = orb;
- this.nameserviceUrl = nameserviceUrl;
- this.listener = listener;
- this.manager = manager;
- this.serviceName = String.format("com/highqsoft/avalon/notification/%s.Notification", serviceName);
- }
-
- /**
- * Connect the event processor to the notification service.
- *
- * @throws NotificationException
- * in case the notification service cannot be connected.
- */
- public synchronized void connect() throws NotificationException {
- if (isConnected()) {
- return;
- }
-
- try {
- NamingContextExt nc = NamingContextExtHelper.narrow(orb.string_to_object(nameserviceUrl));
-
- eventChannel = EventChannelHelper.narrow(nc.resolve(nc.to_name(serviceName)));
-
- proxyPullSupplier = StructuredProxyPullSupplierHelper.narrow(eventChannel.default_consumer_admin()
- .obtain_notification_pull_supplier(ClientType.STRUCTURED_EVENT, new org.omg.CORBA.IntHolder()));
-
- proxyPullSupplier.connect_structured_pull_consumer(this._this(orb));
- connected = true;
- } catch (Exception e) {
- throw new NotificationException("Cannot connect to notification service!", e);
- }
- }
-
- /**
- * Disconnect the event processor from the notification service.
- */
- public synchronized void disconnect() {
- if (isConnected()) {
- if (future != null) {
- future.cancel(false);
- }
-
- proxyPullSupplier = null;
-
- eventChannel._release();
- eventChannel = null;
-
- connected = false;
- }
- }
-
- /**
- * @return true if the event processor is connected to the notification
- * service
- */
- public synchronized boolean isConnected() {
- return connected;
- }
-
- /**
- * Sets the event filter.
- *
- * @param aids
- * List with application element IDs to filter for. Empty list
- * means no all.
- * @param modificationTypes
- * Collection of modification types to filter for.
- * @throws NotificationException
- * if the filter cannot be set
- */
- public void setFilter(List<String> aids, Set<ModificationType> modificationTypes) throws NotificationException {
- if (!isConnected()) {
- throw new IllegalStateException("Cannot set filter when disconnected. Please connect first.");
- }
-
- try {
- FilterFactory filterFactory = eventChannel.default_filter_factory();
- if (filterFactory == null) {
- throw new NotificationException("No default filter factory found!");
- }
-
- Filter filter = filterFactory.create_filter("EXTENDED_TCL");
- filter.add_constraints(new ConstraintExp[] {
- new ConstraintExp(getEventTypes(modificationTypes), getConstraintFilter(aids)) });
- proxyPullSupplier.add_filter(filter);
- } catch (Exception e) {
- throw new NotificationException("Exception when creating filter.", e);
- }
- }
-
- /**
- * Sets the ScheduledFuture that will be used to stop the event processor
- * task.
- *
- * @param future
- * ScheduledFuture
- */
- public void setFuture(ScheduledFuture<?> future) {
- this.future = future;
- }
-
- @Override
- public synchronized void run() {
- if (isConnected()) {
- org.omg.CORBA.BooleanHolder bh = new org.omg.CORBA.BooleanHolder();
-
- try {
- LOGGER.trace("Looking for structured events....");
- // try to pull an event
- StructuredEvent event = proxyPullSupplier.try_pull_structured_event(bh);
- if (bh.value) {
- AvalonNotificationCorbaEvent ev = AvalonNotificationCorbaEventHelper
- .extract(event.remainder_of_body);
- manager.processNotification(ev.mode, ev.aeId, ev.ieId, ev.userId, ev.timestamp, listener);
- } else {
- LOGGER.trace("No structured events found.");
- }
- } catch (Exception e) {
- manager.processException(e);
- }
- } else {
- LOGGER.warn("Disconnected.");
- manager.processException(new NotificationException("Not connected"));
- if (future != null) {
- future.cancel(false);
- }
- }
- }
-
- @Override
- public void disconnect_structured_pull_consumer() {
- LOGGER.info("Disconnected!");
- connected = false;
- }
-
- @Override
- public void offer_change(EventType[] added, EventType[] removed) throws InvalidEventType {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * Constructs a constraint filter.
- *
- * @param aids
- * Application Element IDs used for filtering. Empty list means
- * no filter.
- * @return Constraint filter containing the given aids
- */
- private String getConstraintFilter(List<String> aids) {
- if (aids.isEmpty()) {
- return "TRUE";
- } else {
- return aids.stream().map(aid -> String.format("$.filterable_data(%s) == %s", "ApplicationElement", aid))
- .collect(Collectors.joining(" or "));
- }
- }
-
- /**
- * Converts ModificationTypes in EventTypes.
- *
- * @param modificationTypes
- * @return Array with EventTypes
- */
- private EventType[] getEventTypes(Set<ModificationType> modificationTypes) {
- if (modificationTypes.isEmpty()) {
- return new EventType[0];
- } else {
- return modificationTypes.stream().map(s -> new EventType(eventDomainName, toAvalonString(s)))
- .collect(Collectors.toList()).toArray(new EventType[0]);
- }
- }
-
- /**
- * Converts a {@link ModificationType} enum value to a event type name for
- * the CORBA notification service.
- *
- * @param t
- * a modification type
- * @return event type name
- */
- private String toAvalonString(ModificationType t) {
- switch (t) {
- case INSTANCE_CREATED:
- return "INSERT";
- case INSTANCE_MODIFIED:
- return "REPLACE";
- case INSTANCE_DELETED:
- return "DELETE";
- case SECURITY_MODIFIED:
- return "MODIFYRIGHTS";
- case MODEL_MODIFIED:
- throw new IllegalArgumentException(t.name() + " not supported!");
- default:
- throw new IllegalArgumentException("Invalid enum value!");
- }
- }
-}
+//package org.eclipse.mdm.api.odsadapter.notification.avalon;
+//
+//import java.util.List;
+//import java.util.Set;
+//import java.util.concurrent.ScheduledFuture;
+//import java.util.stream.Collectors;
+//
+//import org.eclipse.mdm.api.base.notification.NotificationException;
+//import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
+//import org.eclipse.mdm.api.base.notification.NotificationListener;
+//import org.omg.CORBA.ORB;
+//import org.omg.CosNaming.NamingContextExt;
+//import org.omg.CosNaming.NamingContextExtHelper;
+//import org.omg.CosNotification.EventType;
+//import org.omg.CosNotification.StructuredEvent;
+//import org.omg.CosNotifyChannelAdmin.ClientType;
+//import org.omg.CosNotifyChannelAdmin.EventChannel;
+//import org.omg.CosNotifyChannelAdmin.EventChannelHelper;
+//import org.omg.CosNotifyChannelAdmin.StructuredProxyPullSupplier;
+//import org.omg.CosNotifyChannelAdmin.StructuredProxyPullSupplierHelper;
+//import org.omg.CosNotifyComm.InvalidEventType;
+//import org.omg.CosNotifyComm.StructuredPullConsumerPOA;
+//import org.omg.CosNotifyFilter.ConstraintExp;
+//import org.omg.CosNotifyFilter.Filter;
+//import org.omg.CosNotifyFilter.FilterFactory;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//
+//import com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent;
+//import com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper;
+//
+///**
+// * Event processor responsible for receiving avalon events from the notification
+// * service and redirect them to the manager.
+// *
+// * @since 1.0.0
+// * @author Matthias Koller, Peak Solution GmbH
+// *
+// */
+//public class EventProcessor extends StructuredPullConsumerPOA implements Runnable {
+//
+// private static final Logger LOGGER = LoggerFactory.getLogger(EventProcessor.class);
+//
+// private static final String eventDomainName = "AVALON";
+//
+// private final ORB orb;
+// private final NotificationListener listener;
+// private final AvalonNotificationManager manager;
+// private final String nameserviceUrl;
+// private final String serviceName;
+//
+// private EventChannel eventChannel;
+// private StructuredProxyPullSupplier proxyPullSupplier;
+//
+// private boolean connected = false;
+//
+// private ScheduledFuture<?> future;
+//
+// /**
+// * Creates a new event processor.
+// *
+// * @param orb
+// * CORBA orb to use
+// * @param listener
+// * notification listener consuming the received events
+// * @param manager
+// * notification manager responsible for processing the events
+// * @param serviceName
+// * service name of the CORBA notification service
+// */
+// public EventProcessor(ORB orb, NotificationListener listener, AvalonNotificationManager manager,
+// String nameserviceUrl, String serviceName) {
+// this.orb = orb;
+// this.nameserviceUrl = nameserviceUrl;
+// this.listener = listener;
+// this.manager = manager;
+// this.serviceName = String.format("com/highqsoft/avalon/notification/%s.Notification", serviceName);
+// }
+//
+// /**
+// * Connect the event processor to the notification service.
+// *
+// * @throws NotificationException
+// * in case the notification service cannot be connected.
+// */
+// public synchronized void connect() throws NotificationException {
+// if (isConnected()) {
+// return;
+// }
+//
+// try {
+// NamingContextExt nc = NamingContextExtHelper.narrow(orb.string_to_object(nameserviceUrl));
+//
+// eventChannel = EventChannelHelper.narrow(nc.resolve(nc.to_name(serviceName)));
+//
+// proxyPullSupplier = StructuredProxyPullSupplierHelper.narrow(eventChannel.default_consumer_admin()
+// .obtain_notification_pull_supplier(ClientType.STRUCTURED_EVENT, new org.omg.CORBA.IntHolder()));
+//
+// proxyPullSupplier.connect_structured_pull_consumer(this._this(orb));
+// connected = true;
+// } catch (Exception e) {
+// throw new NotificationException("Cannot connect to notification service!", e);
+// }
+// }
+//
+// /**
+// * Disconnect the event processor from the notification service.
+// */
+// public synchronized void disconnect() {
+// if (isConnected()) {
+// if (future != null) {
+// future.cancel(false);
+// }
+//
+// proxyPullSupplier = null;
+//
+// eventChannel._release();
+// eventChannel = null;
+//
+// connected = false;
+// }
+// }
+//
+// /**
+// * @return true if the event processor is connected to the notification
+// * service
+// */
+// public synchronized boolean isConnected() {
+// return connected;
+// }
+//
+// /**
+// * Sets the event filter.
+// *
+// * @param aids
+// * List with application element IDs to filter for. Empty list
+// * means no all.
+// * @param modificationTypes
+// * Collection of modification types to filter for.
+// * @throws NotificationException
+// * if the filter cannot be set
+// */
+// public void setFilter(List<String> aids, Set<ModificationType> modificationTypes) throws NotificationException {
+// if (!isConnected()) {
+// throw new IllegalStateException("Cannot set filter when disconnected. Please connect first.");
+// }
+//
+// try {
+// FilterFactory filterFactory = eventChannel.default_filter_factory();
+// if (filterFactory == null) {
+// throw new NotificationException("No default filter factory found!");
+// }
+//
+// Filter filter = filterFactory.create_filter("EXTENDED_TCL");
+// filter.add_constraints(new ConstraintExp[] {
+// new ConstraintExp(getEventTypes(modificationTypes), getConstraintFilter(aids)) });
+// proxyPullSupplier.add_filter(filter);
+// } catch (Exception e) {
+// throw new NotificationException("Exception when creating filter.", e);
+// }
+// }
+//
+// /**
+// * Sets the ScheduledFuture that will be used to stop the event processor
+// * task.
+// *
+// * @param future
+// * ScheduledFuture
+// */
+// public void setFuture(ScheduledFuture<?> future) {
+// this.future = future;
+// }
+//
+// @Override
+// public synchronized void run() {
+// if (isConnected()) {
+// org.omg.CORBA.BooleanHolder bh = new org.omg.CORBA.BooleanHolder();
+//
+// try {
+// LOGGER.trace("Looking for structured events....");
+// // try to pull an event
+// StructuredEvent event = proxyPullSupplier.try_pull_structured_event(bh);
+// if (bh.value) {
+// AvalonNotificationCorbaEvent ev = AvalonNotificationCorbaEventHelper
+// .extract(event.remainder_of_body);
+// manager.processNotification(ev.mode, ev.aeId, ev.ieId, ev.userId, ev.timestamp, listener);
+// } else {
+// LOGGER.trace("No structured events found.");
+// }
+// } catch (Exception e) {
+// manager.processException(e);
+// }
+// } else {
+// LOGGER.warn("Disconnected.");
+// manager.processException(new NotificationException("Not connected"));
+// if (future != null) {
+// future.cancel(false);
+// }
+// }
+// }
+//
+// @Override
+// public void disconnect_structured_pull_consumer() {
+// LOGGER.info("Disconnected!");
+// connected = false;
+// }
+//
+// @Override
+// public void offer_change(EventType[] added, EventType[] removed) throws InvalidEventType {
+// // TODO Auto-generated method stub
+//
+// }
+//
+// /**
+// * Constructs a constraint filter.
+// *
+// * @param aids
+// * Application Element IDs used for filtering. Empty list means
+// * no filter.
+// * @return Constraint filter containing the given aids
+// */
+// private String getConstraintFilter(List<String> aids) {
+// if (aids.isEmpty()) {
+// return "TRUE";
+// } else {
+// return aids.stream().map(aid -> String.format("$.filterable_data(%s) == %s", "ApplicationElement", aid))
+// .collect(Collectors.joining(" or "));
+// }
+// }
+//
+// /**
+// * Converts ModificationTypes in EventTypes.
+// *
+// * @param modificationTypes
+// * @return Array with EventTypes
+// */
+// private EventType[] getEventTypes(Set<ModificationType> modificationTypes) {
+// if (modificationTypes.isEmpty()) {
+// return new EventType[0];
+// } else {
+// return modificationTypes.stream().map(s -> new EventType(eventDomainName, toAvalonString(s)))
+// .collect(Collectors.toList()).toArray(new EventType[0]);
+// }
+// }
+//
+// /**
+// * Converts a {@link ModificationType} enum value to a event type name for
+// * the CORBA notification service.
+// *
+// * @param t
+// * a modification type
+// * @return event type name
+// */
+// private String toAvalonString(ModificationType t) {
+// switch (t) {
+// case INSTANCE_CREATED:
+// return "INSERT";
+// case INSTANCE_MODIFIED:
+// return "REPLACE";
+// case INSTANCE_DELETED:
+// return "DELETE";
+// case SECURITY_MODIFIED:
+// return "MODIFYRIGHTS";
+// case MODEL_MODIFIED:
+// throw new IllegalArgumentException(t.name() + " not supported!");
+// default:
+// throw new IllegalArgumentException("Invalid enum value!");
+// }
+// }
+//}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
index 507265e..05db375 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
@@ -52,6 +52,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Strings;
+
/**
* ODS implementation of the {@link Query} interface.
*
@@ -66,8 +68,10 @@
private static final Logger LOGGER = LoggerFactory.getLogger(ODSQuery.class);
- private static final String GROUPE_NAME = "name";
- private static final Pattern AGGREGATION_NAME_PATTERN = Pattern.compile("\\S+\\((?<" + GROUPE_NAME + ">\\S+)\\)");
+ private static final String GROUP_NAME = "name";
+ private static final String GROUP_AGGRFUNC = "aggrfunc";
+ private static final Pattern AGGREGATION_NAME_PATTERN = Pattern
+ .compile("(?<" + GROUP_AGGRFUNC + ">\\S+)\\((?<" + GROUP_NAME + ">\\S+)\\)");
// ======================================================================
// Instance variables
@@ -323,6 +327,23 @@
return aidName;
}
+
+ private static Aggregation getAggregation(String odsAggrFunc) {
+ switch (Strings.nullToEmpty(odsAggrFunc).trim().toUpperCase()) {
+ case "COUNT": return Aggregation.COUNT;
+ case "DCOUNT": return Aggregation.DISTINCT_COUNT;
+ case "MIN": return Aggregation.MINIMUM;
+ case "MAX": return Aggregation.MAXIMUM;
+ case "AVG": return Aggregation.AVERAGE;
+ case "STDDEV": return Aggregation.DEVIATION;
+ case "SUM": return Aggregation.SUM;
+ case "DISTINCT": return Aggregation.DISTINCT;
+ default:
+ throw new IllegalArgumentException("Unsupported aggregate function '" +
+ Strings.nullToEmpty(odsAggrFunc).trim().toUpperCase() + "'!");
+ }
+
+ }
// ======================================================================
// Inner classes
@@ -436,9 +457,15 @@
private RecordFactory(EntityType entityType, NameValueSeqUnitId[] nvsuis) throws DataAccessException {
this.entityType = entityType;
for (NameValueSeqUnitId nvsui : nvsuis) {
+ String attributeName = nvsui.valName;
+ Aggregation aggregation = Aggregation.NONE;
Matcher matcher = AGGREGATION_NAME_PATTERN.matcher(nvsui.valName);
- String attributeName = matcher.matches() ? matcher.group(GROUPE_NAME) : nvsui.valName;
- valueFactories.add(new ValueFactory(entityType.getAttribute(attributeName), nvsui));
+ if (matcher.matches()) {
+ attributeName = matcher.group(GROUP_NAME);
+ aggregation = ODSQuery.getAggregation(matcher.group(GROUP_AGGRFUNC));
+ }
+
+ valueFactories.add(new ValueFactory(entityType.getAttribute(attributeName), aggregation, nvsui));
}
}
@@ -489,10 +516,10 @@
* @throws DataAccessException
* Thrown on conversion errors.
*/
- private ValueFactory(Attribute attribute, NameValueSeqUnitId nvsui) throws DataAccessException {
+ private ValueFactory(Attribute attribute, Aggregation aggregation, NameValueSeqUnitId nvsui) throws DataAccessException {
length = nvsui.value.flag.length;
unit = attribute.getUnit();
- values = ODSConverter.fromODSValueSeq(attribute, unit, nvsui.value);
+ values = ODSConverter.fromODSValueSeq(attribute, aggregation, unit, nvsui.value);
}
// ======================================================================
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
index 7a56c1f..ac905c4 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
@@ -133,13 +133,12 @@
List<CatalogSensor> catalogSensors = (List<CatalogSensor>) entitiesByClassType.get(CatalogSensor.class);
if (catalogSensors != null) {
- // TODO avalon 4.3b throws an exception in
- // AoSession.commintTransaction() if multiple
+ // TODO anehmer on 2017-11-16: avalon 4.3b throws an exception in
+ // AoSession.commitTransaction() if multiple
// catalog sensors have been deleted and leaves the application
- // model in a broken state
-
- // getCatalogManager().createCatalogSensors(catalogSensors);
- throw new DataAccessException("CURRENTLY NOT IMPLEMENTED");
+ // model in a broken state. This is also stated in the documentation. This
+ // comment should be removed later.
+ getCatalogManager().createCatalogSensors(catalogSensors);
}
List<CatalogAttribute> catalogAttributes = (List<CatalogAttribute>) entitiesByClassType
@@ -217,7 +216,6 @@
getUploadService().upload(filtered, null);
}
}
-
executeStatements(et -> new UpdateStatement(this, et, false), entities);
} catch (AoException e) {
throw new DataAccessException("Unable to update entities due to: " + e.reason, e);
@@ -251,13 +249,12 @@
List<CatalogSensor> catalogSensors = (List<CatalogSensor>) entitiesByClassType.get(CatalogSensor.class);
if (catalogSensors != null) {
- // TODO avalon 4.3b throws an exception in
- // AoSession.commintTransaction() if multiple
+ // TODO anehmer on 2017-11-16: avalon 4.3b throws an exception in
+ // AoSession.commitTransaction() if multiple
// catalog sensors have been deleted and leaves the application
- // model in a broken state
-
- // getCatalogManager().deleteCatalogSensors(catalogSensors);
- throw new DataAccessException("CURRENTLY NOT IMPLEMENTED");
+ // model in a broken state. This is also stated in the documentation. This
+ // comment should be removed later.
+ getCatalogManager().deleteCatalogSensors(catalogSensors);
}
List<CatalogAttribute> catalogAttributes = (List<CatalogAttribute>) entitiesByClassType
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
index ea597b6..819b6bd 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
@@ -218,13 +218,14 @@
for (Entry<Class<? extends Deletable>, List<? extends Deletable>> entry : core.getChildrenStore().getCurrent()
.entrySet()) {
- Map<Boolean, List<Entity>> patrition = entry.getValue().stream()
+ Map<Boolean, List<Entity>> partition = entry.getValue()
+ .stream()
.collect(Collectors.partitioningBy(e -> ODSUtils.isValidID(e.getID())));
- List<Entity> virtualEntities = patrition.get(Boolean.TRUE);
+ List<Entity> virtualEntities = partition.get(Boolean.FALSE);
if (virtualEntities != null && !virtualEntities.isEmpty()) {
childrenToCreate.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).addAll(virtualEntities);
}
- List<Entity> existingEntities = patrition.get(Boolean.FALSE);
+ List<Entity> existingEntities = partition.get(Boolean.TRUE);
if (existingEntities != null && !existingEntities.isEmpty()) {
childrenToUpdate.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).addAll(existingEntities);
}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java b/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
index 986e6af..c62c05f 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
@@ -41,9 +41,12 @@
import org.eclipse.mdm.api.base.model.ScalarType;
import org.eclipse.mdm.api.base.model.Value;
import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Aggregation;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.odsadapter.query.ODSAttribute;
+import com.google.common.collect.Sets;
+
/**
* Utility class for value conversions from/to ODS types.
*
@@ -91,6 +94,8 @@
*
* @param attribute
* The {@link Attribute}.
+ * @param aggregation
+ * The {@link Aggregation} used when the values were obtained.
* @param unit
* The unit name.
* @param odsValueSeq
@@ -99,35 +104,41 @@
* @throws DataAccessException
* Thrown on conversion errors.
*/
- public static List<Value> fromODSValueSeq(Attribute attribute, String unit, TS_ValueSeq odsValueSeq)
+ public static List<Value> fromODSValueSeq(Attribute attribute, Aggregation aggregation, String unit, TS_ValueSeq odsValueSeq)
throws DataAccessException {
DataType dataType = odsValueSeq.u.discriminator();
short[] flags = odsValueSeq.flag;
List<Value> values = new ArrayList<>(flags.length);
- if (((ODSAttribute) attribute).isIdAttribute()) {
+ if (((ODSAttribute) attribute).isIdAttribute() && Sets
+ .immutableEnumSet(Aggregation.MINIMUM, Aggregation.MAXIMUM, Aggregation.DISTINCT, Aggregation.NONE)
+ .contains(aggregation)) {
if (DataType.DT_LONGLONG == dataType) {
T_LONGLONG[] odsValues = odsValueSeq.u.longlongVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, Long.toString(fromODSLong(odsValues[i]))));
+ values.add(createValue(attribute, aggregation, DataType.DT_STRING, unit, flags[i] == 15,
+ Long.toString(fromODSLong(odsValues[i]))));
}
return values;
} else if (DataType.DS_LONGLONG == dataType) {
T_LONGLONG[][] odsValues = odsValueSeq.u.longlongSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, toString(odsValues[i])));
+ values.add(createValue(attribute, aggregation, DataType.DS_STRING, unit, flags[i] == 15,
+ toString(odsValues[i])));
}
return values;
} else if (DataType.DT_LONG == dataType) {
int[] odsValues = odsValueSeq.u.longVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, Integer.toString(odsValues[i])));
+ values.add(createValue(attribute, aggregation, DataType.DT_STRING, unit, flags[i] == 15,
+ Integer.toString(odsValues[i])));
}
return values;
} else if (DataType.DS_LONG == dataType) {
int[][] odsValues = odsValueSeq.u.longSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, toString(odsValues[i])));
+ values.add(createValue(attribute, aggregation, DataType.DS_STRING, unit, flags[i] == 15,
+ toString(odsValues[i])));
}
return values;
}
@@ -136,149 +147,149 @@
if (DataType.DT_STRING == dataType) {
String[] odsValues = odsValueSeq.u.stringVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_STRING == dataType) {
String[][] odsValues = odsValueSeq.u.stringSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_DATE == dataType) {
String[] odsValues = odsValueSeq.u.dateVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSDate(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSDate(odsValues[i])));
}
} else if (DataType.DS_DATE == dataType) {
String[][] odsValues = odsValueSeq.u.dateSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSDateSeq(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSDateSeq(odsValues[i])));
}
} else if (DataType.DT_BOOLEAN == dataType) {
boolean[] odsValues = odsValueSeq.u.booleanVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_BOOLEAN == dataType) {
boolean[][] odsValues = odsValueSeq.u.booleanSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_BYTE == dataType) {
byte[] odsValues = odsValueSeq.u.byteVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_BYTE == dataType) {
byte[][] odsValues = odsValueSeq.u.byteSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_SHORT == dataType) {
short[] odsValues = odsValueSeq.u.shortVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_SHORT == dataType) {
short[][] odsValues = odsValueSeq.u.shortSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_LONG == dataType) {
int[] odsValues = odsValueSeq.u.longVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_LONG == dataType) {
int[][] odsValues = odsValueSeq.u.longSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_LONGLONG == dataType) {
T_LONGLONG[] odsValues = odsValueSeq.u.longlongVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSLong(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSLong(odsValues[i])));
}
} else if (DataType.DS_LONGLONG == dataType) {
T_LONGLONG[][] odsValues = odsValueSeq.u.longlongSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSLongSeq(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSLongSeq(odsValues[i])));
}
} else if (DataType.DT_FLOAT == dataType) {
float[] odsValues = odsValueSeq.u.floatVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_FLOAT == dataType) {
float[][] odsValues = odsValueSeq.u.floatSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_DOUBLE == dataType) {
double[] odsValues = odsValueSeq.u.doubleVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_DOUBLE == dataType) {
double[][] odsValues = odsValueSeq.u.doubleSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_BYTESTR == dataType) {
byte[][] odsValues = odsValueSeq.u.bytestrVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DS_BYTESTR == dataType) {
byte[][][] odsValues = odsValueSeq.u.bytestrSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, odsValues[i]));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
}
} else if (DataType.DT_COMPLEX == dataType) {
T_COMPLEX[] odsValues = odsValueSeq.u.complexVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSFloatComplex(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSFloatComplex(odsValues[i])));
}
} else if (DataType.DS_COMPLEX == dataType) {
T_COMPLEX[][] odsValues = odsValueSeq.u.complexSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSFloatComplexSeq(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSFloatComplexSeq(odsValues[i])));
}
} else if (DataType.DT_DCOMPLEX == dataType) {
T_DCOMPLEX[] odsValues = odsValueSeq.u.dcomplexVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSDoubleComplex(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSDoubleComplex(odsValues[i])));
}
} else if (DataType.DS_DCOMPLEX == dataType) {
T_DCOMPLEX[][] odsValues = odsValueSeq.u.dcomplexSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSDoubleComplexSeq(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSDoubleComplexSeq(odsValues[i])));
}
} else if (DataType.DT_ENUM == dataType) {
int[] odsValues = odsValueSeq.u.enumVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15,
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
ODSEnumerations.fromODSEnum(attribute.getEnumObj(), odsValues[i])));
}
} else if (DataType.DS_ENUM == dataType) {
int[][] odsValues = odsValueSeq.u.enumSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15,
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
ODSEnumerations.fromODSEnumSeq(attribute.getEnumObj(), odsValues[i])));
}
} else if (DataType.DT_EXTERNALREFERENCE == dataType) {
T_ExternalReference[] odsValues = odsValueSeq.u.extRefVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSExternalReference(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSExternalReference(odsValues[i])));
}
} else if (DataType.DS_EXTERNALREFERENCE == dataType) {
T_ExternalReference[][] odsValues = odsValueSeq.u.extRefSeq();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSExternalReferenceSeq(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSExternalReferenceSeq(odsValues[i])));
}
} else if (DataType.DT_BLOB == dataType) {
Blob[] odsValues = odsValueSeq.u.blobVal();
for (int i = 0; i < flags.length; i++) {
- values.add(attribute.createValue(unit, flags[i] == 15, fromODSBlob(odsValues[i])));
+ values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSBlob(odsValues[i])));
}
} else {
throw new DataAccessException("Conversion for ODS data type '" + dataType.toString() + "' does not exist.");
@@ -286,6 +297,44 @@
return values;
}
+
+ /**
+ * Creates a {@link Value} from the input.
+ *
+ * @param attribute
+ * The {@link Attribute}
+ * @param aggregation
+ * The {@link Aggregation} used when the input values were obtained
+ * @param dataType
+ * The {@link DataType} associated with the input value, evaluated
+ * only if aggregation != {@code Aggregation.NONE}, otherwise that of
+ * the attribute is used
+ * @param unit
+ * The unit of the input value
+ * @param valid
+ * The validity flag of the input value
+ * @param input
+ * The input value
+ * @return The {@link Value} created.
+ */
+ private static Value createValue(Attribute attribute, Aggregation aggregation, DataType dataType, String unit,
+ boolean valid, Object input) {
+ if (Aggregation.NONE == aggregation) {
+ return attribute.createValue(unit, valid, input);
+ } else {
+ ValueType<?> valueType = ODSUtils.VALUETYPES.revert(dataType);
+ if (valueType.isEnumerationType()
+ && attribute.getValueType().isEnumerationType()
+ && Sets.immutableEnumSet(Aggregation.MINIMUM, Aggregation.MAXIMUM, Aggregation.DISTINCT)
+ .contains(aggregation)) {
+ return valueType.create(String.format("%s(%s)", aggregation.name(), attribute.getName()), unit, valid,
+ input, attribute.getEnumObj().getName());
+ } else {
+ return valueType.create(String.format("%s(%s)", aggregation.name(), attribute.getName()), unit, valid,
+ input);
+ }
+ }
+ }
private static String[] toString(int[] odsValues) {
return IntStream.of(odsValues).mapToObj(Integer::toString).toArray(String[]::new);
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/AggregationTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/AggregationTest.java
new file mode 100644
index 0000000..89a8f8b
--- /dev/null
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/AggregationTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018 Peak Solution GmbH
+ * 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
+ */
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+/**
+ * Aggregation test
+ *
+ * @since 1.0.0
+ * @author maf, Peak Solution GmbH
+ */
+@Ignore
+// FIXME 11.01.2018: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class AggregationTest {
+
+ private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+ private static final String USER = "sa";
+ private static final String PASSWORD = "sa";
+
+ private static ApplicationContext context;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws ConnectionException {
+ String nameServiceHost = System.getProperty("host");
+ String nameServicePort = System.getProperty("port");
+ String serviceName = System.getProperty("service");
+
+ if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+ throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+ }
+
+ nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+ if (nameServicePort == null || nameServicePort.isEmpty()) {
+ throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+ }
+
+ if (serviceName == null || serviceName.isEmpty()) {
+ throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+ }
+
+ Map<String, String> connectionParameters = new HashMap<>();
+ connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+ connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+ connectionParameters.put(PARAM_USER, USER);
+ connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+ context = new ODSContextFactory().connect(connectionParameters);
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws ConnectionException {
+ if (context != null) {
+ context.close();
+ }
+ }
+
+ @org.junit.Test
+ public void testQueryIdAndNameNoAggregation() throws DataAccessException {
+ ModelManager modelManager = context.getModelManager().get();
+ QueryService queryService = context.getQueryService().get();
+
+ EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+ Attribute idAttribute = unitEntityType.getAttribute("Id");
+ Attribute nameAttribute = unitEntityType.getAttribute("Name");
+
+ List<Result> listRes = queryService.createQuery()
+ .select(idAttribute)
+ .select(nameAttribute)
+ .fetch();
+
+ assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+ assertThat(listRes.get(0).getValue(idAttribute).getValueType()).isEqualTo(ValueType.STRING);
+ // Test retrieving attribute value with Aggregation.NONE (should yield the same result as with no aggregation):
+ assertThat(listRes.get(0).getValue(idAttribute, Aggregation.NONE).getValueType()).isEqualTo(ValueType.STRING);
+ assertThat(listRes.get(0).getValue(nameAttribute).getValueType()).isEqualTo(ValueType.STRING);
+ }
+
+ @org.junit.Test
+ public void testQueryIdWithAggregation() throws DataAccessException {
+ ModelManager modelManager = context.getModelManager().get();
+ QueryService queryService = context.getQueryService().get();
+
+ EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+ Attribute idAttribute = unitEntityType.getAttribute("Id");
+
+ List<Result> listRes = queryService.createQuery()
+ .select(idAttribute, Aggregation.MAXIMUM) // should be a string in result, just like non-aggregated Id attribute
+ .select(idAttribute, Aggregation.AVERAGE) // should be a numeric value in result
+ .fetch();
+
+ assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+ assertThat(listRes.get(0).getValue(idAttribute, Aggregation.MAXIMUM).getValueType()).isEqualTo(ValueType.STRING);
+ assertThat(listRes.get(0).getValue(idAttribute, Aggregation.AVERAGE).getValueType()).isEqualTo(ValueType.LONG);
+ }
+
+ @org.junit.Test
+ public void testQueryFactorWithAggregation() throws DataAccessException {
+ ModelManager modelManager = context.getModelManager().get();
+ QueryService queryService = context.getQueryService().get();
+
+ EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+ Attribute factorAttribute = unitEntityType.getAttribute("Factor");
+
+ List<Result> listRes = queryService.createQuery()
+ .select(factorAttribute, Aggregation.COUNT)
+ .group(factorAttribute)
+ .fetch();
+
+ assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+ assertThat(listRes.get(0).getValue(factorAttribute, Aggregation.COUNT).getValueType()).isEqualTo(ValueType.INTEGER);
+ }
+
+ @org.junit.Test
+ public void testQueryFactorWithAndWithoutAggregation() throws DataAccessException {
+ ModelManager modelManager = context.getModelManager().get();
+ QueryService queryService = context.getQueryService().get();
+
+ EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+ Attribute factorAttribute = unitEntityType.getAttribute("Factor");
+
+ List<Result> listRes = queryService.createQuery()
+ .select(factorAttribute)
+ .select(factorAttribute, Aggregation.SUM)
+ .group(factorAttribute)
+ .fetch();
+
+
+ assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+ assertThat(listRes.get(0).getValue(factorAttribute).getValueType()).isEqualTo(ValueType.DOUBLE);
+ assertThat(listRes.get(0).getValue(factorAttribute, Aggregation.SUM).getValueType()).isEqualTo(ValueType.DOUBLE);
+ }
+
+}
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/ODSContextTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/ODSContextTest.java
new file mode 100644
index 0000000..cafc650
--- /dev/null
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/ODSContextTest.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Peak Solution GmbH
+ * 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
+ *
+ *******************************************************************************/
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.asam.ods.AoException;
+import org.asam.ods.InstanceElement;
+import org.assertj.core.api.Condition;
+import org.assertj.core.api.Fail;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.mockito.Mockito;
+
+@Ignore
+//FIXME 26.01.2018: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+//Comment this in for local tests only.
+public class ODSContextTest {
+
+ /*
+ * ATTENTION: ==========
+ *
+ * To run this test make sure the target service is running a MDM default
+ * model and any database constraint which enforces a relation of Test to a
+ * parent entity is deactivated!
+ */
+ private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+ private static final String USER = "sa";
+ private static final String PASSWORD = "sa";
+
+ private static ApplicationContext context;
+ private static EntityManager entityManager;
+
+ private static String nameServiceHost = System.getProperty("host");
+ private static String nameServicePort = System.getProperty("port");
+ private static String serviceName = System.getProperty("service");
+
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws ConnectionException {
+
+ if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+ throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+ }
+
+ nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+ if (nameServicePort == null || nameServicePort.isEmpty()) {
+ throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+ }
+
+ if (serviceName == null || serviceName.isEmpty()) {
+ throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+ }
+
+ Map<String, String> connectionParameters = new HashMap<>();
+ connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+ connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+ connectionParameters.put(PARAM_USER, USER);
+ connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+ context = new ODSContextFactory().connect(connectionParameters);
+ entityManager = context.getEntityManager()
+ .orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws ConnectionException {
+ if (context != null) {
+ context.close();
+ }
+ }
+
+ @org.junit.Test
+ public void testGetAdapterType() {
+ assertThat(context.getAdapterType()).isEqualTo("ods");
+ }
+
+ @org.junit.Test
+ public void testGetLink() {
+ // we assume a test with ID 4 exists.
+ Test test = entityManager.load(Test.class, "4");
+
+ Map<Entity, String> asamPaths = entityManager.getLinks(Arrays.asList(test));
+
+ assertThat(asamPaths)
+ .hasSize(1)
+ .containsOnlyKeys(test)
+ .hasEntrySatisfying(test, new Condition<String>(s -> s.startsWith(getLinkPrefix()), ""));
+ }
+
+ @org.junit.Test
+ public void testGetLinkAndLoadOdsInstance() {
+ // we assume a test with ID 4 exists.
+ long testId = 4L;
+ Test test = entityManager.load(Test.class, Long.toString(testId));
+
+ Map<Entity, String> asamPaths = entityManager.getLinks(Arrays.asList(test));
+
+ assertThat(asamPaths)
+ .hasSize(1)
+ .containsOnlyKeys(test)
+ .hasEntrySatisfying(test, new Condition<String>(s -> s.startsWith(getLinkPrefix()), ""));
+ // We try to load the instance from the ODS Server with the AsamPath, but without the service prefix
+ String asamPathWithoutService = asamPaths.get(test).replace(getLinkPrefix(), "");
+
+ try {
+ InstanceElement ie = ((ODSContext) context).getAoSession().getApplicationStructure().getInstanceByAsamPath(asamPathWithoutService);
+ assertThat(ODSConverter.fromODSLong(ie.getId())).isEqualTo(testId);
+ } catch (AoException e) {
+ Fail.fail("Instance with AsamPath '" + asamPathWithoutService + "' could not be loaded. Reason: " + e.reason, e);
+ }
+ }
+
+ @org.junit.Test(expected=IllegalArgumentException.class)
+ public void testGetLinksWithInvalidType() {
+ // we assume a test with ID 4 exists.
+ Test test = entityManager.load(Test.class, "4");
+ BaseEntity entity = Mockito.mock(BaseEntity.class);
+ // Mock an entity with a non existing TypeName
+ when(entity.getTypeName()).thenReturn("invalidType");
+
+ entityManager.getLinks(Arrays.asList(test, entity));
+ }
+
+ @org.junit.Test
+ public void testGetLinksWithEnitityWithMissingId() {
+ // we assume a test with ID 4 exists.
+ Test test = entityManager.load(Test.class, "4");
+
+ // Mock an entity with a non existing ID
+ TestStep testStep = Mockito.mock(TestStep.class);
+ when(testStep.getID()).thenReturn("-1");
+
+ Map<Entity, String> asamPaths = entityManager.getLinks(Arrays.asList(test, testStep));
+
+ assertThat(asamPaths)
+ .hasSize(1)
+ .containsOnlyKeys(test)
+ .hasEntrySatisfying(test, new Condition<String>(s -> s.startsWith(getLinkPrefix()), ""));
+ }
+
+ private String getLinkPrefix() {
+ return String.format("corbaloc::1.2@%s:%s/NameService/%s.ASAM-ODS", nameServiceHost, nameServicePort, serviceName);
+ }
+}
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
index 2478683..c8234d2 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
@@ -16,6 +16,7 @@
import org.asam.ods.TS_UnionSeq;
import org.asam.ods.TS_ValueSeq;
+import org.eclipse.mdm.api.base.query.Aggregation;
import org.eclipse.mdm.api.odsadapter.query.ODSAttribute;
import org.junit.Test;
@@ -25,7 +26,7 @@
public void testFromODSValueSeqODSDateYear() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("2017"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("2017"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 1, 1, 0, 0)));
}
@@ -34,7 +35,7 @@
public void testFromODSValueSeqODSDateMonth() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("201710"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("201710"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 1, 0, 0)));
}
@@ -43,7 +44,7 @@
public void testFromODSValueSeqODSDate() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171004"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171004"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 0, 0)));
}
@@ -52,7 +53,7 @@
public void testFromODSValueSeqODSDateHour() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("2017100412"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("2017100412"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 0)));
}
@@ -61,7 +62,7 @@
public void testFromODSValueSeqODSDateMinute() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("201710041213"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("201710041213"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13)));
}
@@ -70,7 +71,7 @@
public void testFromODSValueSeqODSDateSecond() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171004121314"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171004121314"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13, 14, 0)));
}
@@ -79,7 +80,7 @@
public void testFromODSValueSeqODSDateMillisecond() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171004121314123"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171004121314123"));
verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13, 14, 123_000_000)));
}
@@ -88,14 +89,14 @@
public void testFromODSValueSeqInvalidLength() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("201710041"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("201710041"));
}
@Test(expected = IllegalArgumentException.class)
public void testFromODSValueSeqInvalidMonth() throws Exception {
ODSAttribute attr = mock(ODSAttribute.class);
- ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171304"));
+ ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171304"));
}
private TS_ValueSeq getTS_ValueSeqFromDates(String... dates) {