Merge branch 'dev'
Change-Id: Icc746729170e28a6da5e892c8c726fb3991c7d16
diff --git a/build.gradle b/build.gradle
index 9cd5fb0..7f7632b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,7 +14,7 @@
description = 'MDM API - ODSAdapter'
group = 'org.eclipse.mdm'
-version = '5.0.0'
+version = '5.1.0M1-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'maven'
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 de1df72..bb7b141 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
@@ -1,16 +1,16 @@
-/********************************************************************************
- * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
package org.eclipse.mdm.api.odsadapter;
@@ -34,15 +34,7 @@
import org.eclipse.mdm.api.base.Transaction;
import org.eclipse.mdm.api.base.adapter.EntityType;
import org.eclipse.mdm.api.base.massdata.ReadRequest;
-import org.eclipse.mdm.api.base.model.Channel;
-import org.eclipse.mdm.api.base.model.ChannelGroup;
-import org.eclipse.mdm.api.base.model.ContextDescribable;
-import org.eclipse.mdm.api.base.model.ContextRoot;
-import org.eclipse.mdm.api.base.model.ContextType;
-import org.eclipse.mdm.api.base.model.Entity;
-import org.eclipse.mdm.api.base.model.Environment;
-import org.eclipse.mdm.api.base.model.MeasuredValues;
-import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.model.*;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.base.query.Filter;
import org.eclipse.mdm.api.base.query.JoinType;
@@ -51,6 +43,8 @@
import org.eclipse.mdm.api.base.query.Record;
import org.eclipse.mdm.api.base.query.Result;
import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.Classification;
+import org.eclipse.mdm.api.dflt.model.Status;
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;
@@ -80,7 +74,7 @@
// Instance variables
// ======================================================================
private final Transfer transfer = Transfer.SOCKET;
-
+
private final ODSContext context;
private final ODSModelManager odsModelManager;
private final QueryService queryService;
@@ -199,35 +193,39 @@
return entityLoader.loadAll(new Key<>(entityClass), pattern);
}
- // /**
- // * {@inheritDoc}
- // */
- // @Override
- // public <T extends StatusAttachable> List<T> loadAll(Class<T> entityClass,
- // Status status, String pattern)
- // throws DataAccessException {
- // EntityType entityType = modelManager.getEntityType(entityClass);
- // EntityType statusEntityType =
- // modelManager.getEntityType(status.getTypeName());
- //
- // List<String> instanceIDs = modelManager.createQuery()
- // .join(entityType, statusEntityType).selectID(entityType)
- // .fetch(Filter.and()
- // .id(statusEntityType, status.getID())
- // .name(entityType, pattern))
- // .stream().map(r ->
- // r.getRecord(entityType)).map(Record::getID).collect(Collectors.toList());
- //
- // return entityLoader.loadAll(new Key<>(entityClass), instanceIDs);
- // }
- //
- // @Override
- // public List<Status> loadAllStatus(Class<? extends StatusAttachable>
- // entityClass, String pattern)
- // throws DataAccessException {
- // return entityLoader.loadAll(new Key<>(Status.class, entityClass),
- // pattern);
- // }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T extends StatusAttachable> List<T> loadAll(Class<T> entityClass, Status status, String pattern)
+ throws DataAccessException {
+ EntityType entityType = odsModelManager.getEntityType(entityClass);
+ EntityType classificationType = odsModelManager.getEntityType(Classification.class);
+ EntityType statusEntityType =
+ odsModelManager.getEntityType(status.getTypeName());
+
+ List<String> instanceIDs = queryService.createQuery()
+ .join(entityType, classificationType)
+ .join(classificationType, statusEntityType)
+ .selectID(entityType)
+ .fetch(Filter.and()
+ .id(statusEntityType, status.getID())
+ .name(entityType, pattern))
+ .stream().map(r ->
+ r.getRecord(entityType)).map(Record::getID).collect(Collectors.toList());
+
+ return entityLoader.loadAll(new Key<>(entityClass), instanceIDs);
+ }
+
+/*
+ @Override
+ public List<Status> loadAllStatus(Class<? extends StatusAttachable>
+ entityClass, String pattern)
+ throws DataAccessException {
+ return entityLoader.loadAll(new Key<>(Status.class, entityClass),
+ pattern);
+ }
+ */
/**
* {@inheritDoc}
@@ -376,7 +374,7 @@
/**
* 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>
+ * <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
@@ -385,33 +383,33 @@
*/
@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)
+
+ 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();
@@ -424,7 +422,7 @@
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 4f0b644..1ebf4ee 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
@@ -1,16 +1,16 @@
-/********************************************************************************
- * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
package org.eclipse.mdm.api.odsadapter.filetransfer;
@@ -20,9 +20,15 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
+import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
import org.asam.ods.AoSession;
import org.asam.ods.ElemId;
import org.eclipse.mdm.api.base.ServiceNotProvidedException;
@@ -61,6 +67,7 @@
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;
+ private static final String INTERFACE_NAME_PROPERTY = "org.eclipse.mdm.api.odsadapter.filetransfer.interfaceName";
private final CORBAFileServerIF fileServer;
private final AoSession aoSession;
@@ -73,7 +80,7 @@
/**
* Constructor.
*
- * @param modelManager
+ * @param context
* Used for setup.
* @param transfer
* The transfer type for up- and downloads.
@@ -83,7 +90,7 @@
if (!(mm instanceof ODSModelManager)) {
throw new IllegalArgumentException("The supplied ModelManager must be an ODSModelManager!");
}
-
+
fileServer = context.getFileServer();
aoSession = context.getAoSession();
orb = context.getORB();
@@ -91,7 +98,7 @@
bufferSize = getBufferSize();
}
-
+
/**
* Opens a consumable download {@link InputStream} for given
* {@link FileLink}.
@@ -212,7 +219,7 @@
*/
private InputStream openSocketStream(FileLink fileLink, ElemId elemId) throws IOException {
// auto assigned port with awaiting exactly ONE incoming connection
- try (ServerSocket serverSocket = new ServerSocket(0, 1)) {
+ try (ServerSocket serverSocket = new ServerSocket(0, 1, getInterfaceAddress())) {
serverSocket.setSoTimeout(SOCKET_TIMEOUT * 6);
new Thread(() -> {
@@ -235,6 +242,60 @@
}
}
+ private InetAddress getInterfaceAddress() throws SocketException {
+ String property = System.getProperty(INTERFACE_NAME_PROPERTY);
+ if (StringUtils.isEmpty(property)) {
+ LOGGER.debug("Using no specified interface for file transfer, property not set.");
+ return null;
+ }
+ List<NetworkInterface> interfaces = getInterfaceList();
+ List<NetworkInterface> filteredInterfaces = getFilteredInterfaces(interfaces);
+ for (NetworkInterface filteredInterface : filteredInterfaces) {
+ if (filteredInterface.getName().equals(property)
+ && filteredInterface.getInetAddresses().hasMoreElements()) {
+ InetAddress inetAddress = filteredInterface.getInetAddresses().nextElement();
+ LOGGER.debug("Using interface {} with address {} for file transfer.", filteredInterface.getName(),
+ inetAddress);
+ return inetAddress;
+ }
+ }
+ return getFallback(filteredInterfaces);
+ }
+
+ private InetAddress getFallback(List<NetworkInterface> filteredInterfaces) {
+ if (filteredInterfaces.isEmpty()) {
+ LOGGER.debug("Using no specified interface for file transfer, property set but no running interface.");
+ return null;
+ }
+ NetworkInterface networkInterface = filteredInterfaces.get(0);
+ Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
+ if (inetAddresses.hasMoreElements()) {
+ InetAddress address = inetAddresses.nextElement();
+ LOGGER.debug("Using interface {} with address {} for file transfer.", networkInterface.getName(), address);
+ return address;
+ }
+ return null;
+ }
+
+ private List<NetworkInterface> getFilteredInterfaces(List<NetworkInterface> interfaces) throws SocketException {
+ List<NetworkInterface> filteredInterfaces = new ArrayList<>();
+ for (NetworkInterface anInterface : interfaces) {
+ if (anInterface.isUp() && !anInterface.isLoopback() && !anInterface.isVirtual()) {
+ filteredInterfaces.add(anInterface);
+ }
+ }
+ return filteredInterfaces;
+ }
+
+ private List<NetworkInterface> getInterfaceList() throws SocketException {
+ List<NetworkInterface> result = new ArrayList<>();
+ Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ while (networkInterfaces.hasMoreElements()) {
+ result.add(networkInterfaces.nextElement());
+ }
+ return result;
+ }
+
/**
* Uploads given {@link InputStream} for given {@link FileLink} using the
* {@link CORBAFileServerIF}.
@@ -274,7 +335,7 @@
*/
private String uploadVIASocket(InputStream inputStream, FileLink fileLink, ElemId elemId) throws IOException {
// auto assigned port with awaiting exactly ONE incoming connection
- try (ServerSocket serverSocket = new ServerSocket(0, 1)) {
+ try (ServerSocket serverSocket = new ServerSocket(0, 1, getInterfaceAddress())) {
serverSocket.setSoTimeout(SOCKET_TIMEOUT * 6);
new Thread(() -> {
@@ -290,11 +351,14 @@
}
}).start();
+ int localPort = serverSocket.getLocalPort();
+ String localHostName = serverSocket.getInetAddress().getHostName();
try {
return fileServer.saveForInstanceBySocket(aoSession, fileLink.getFileName(), "", elemId.aid, elemId.iid,
- InetAddress.getLocalHost().getHostAddress(), serverSocket.getLocalPort());
+ localHostName, localPort);
} catch (CORBAFileServerException e) {
- throw new IOException("Unable to upload file via socket due to: " + e.reason, e);
+ String message = String.format("Unable to upload file via socket to %s:%d due to: %s", localHostName, localPort, e.reason);
+ throw new IOException(message, e);
}
}
}
@@ -333,7 +397,7 @@
private InputStreamAdapter(InputStreamIF inputStream) {
this.inputStream = inputStream;
}
-
+
/**
* {@inheritDoc}
*/
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
index 10521c1..b2f6b92 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
@@ -121,12 +121,12 @@
List<String> testStepIDs = queryService.createQuery().selectID(testStep)
.join(testStep.getRelation(contextRoot), JoinType.OUTER)
- .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids)))
+ .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids.toArray(new String[0]))))
.stream().map(r -> r.getRecord(testStep)).map(Record::getID).collect(Collectors.toList());
List<String> measurementIDs = queryService.createQuery().selectID(measurement)
.join(measurement.getRelation(contextRoot), JoinType.OUTER)
- .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids)))
+ .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids.toArray(new String[0]))))
.stream().map(r -> r.getRecord(measurement)).map(Record::getID).collect(Collectors.toList());
List<ContextDescribable> list = new ArrayList<>();
@@ -159,13 +159,13 @@
List<String> testStepIDs = queryService.createQuery().selectID(testStep)
.join(testStep.getRelation(contextRoot), JoinType.OUTER)
.join(contextRoot.getRelation(contextComponent), JoinType.OUTER)
- .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(), ids)))
+ .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(), ids.toArray(new String[0]))))
.stream().map(r -> r.getRecord(testStep)).map(Record::getID).collect(Collectors.toList());
List<String> measurementIDs = queryService.createQuery().selectID(measurement)
.join(measurement.getRelation(contextRoot), JoinType.OUTER)
.join(contextRoot.getRelation(contextComponent), JoinType.OUTER)
- .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(), ids)))
+ .fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(), ids.toArray(new String[0]))))
.stream().map(r -> r.getRecord(measurement)).map(Record::getID).collect(Collectors.toList());
List<ContextDescribable> list = new ArrayList<>();
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
index 1dc169f..6efe7f3 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
@@ -1,16 +1,16 @@
-/********************************************************************************
- * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
package org.eclipse.mdm.api.odsadapter.query;
@@ -24,13 +24,10 @@
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Stream;
-import com.google.common.base.Stopwatch;
-import org.apache.commons.lang3.time.StopWatch;
import org.asam.ods.AIDName;
import org.asam.ods.AggrFunc;
import org.asam.ods.AoException;
@@ -75,8 +72,12 @@
import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
import org.eclipse.mdm.api.dflt.model.CatalogComponent;
import org.eclipse.mdm.api.dflt.model.CatalogSensor;
+import org.eclipse.mdm.api.dflt.model.Classification;
+import org.eclipse.mdm.api.dflt.model.Domain;
import org.eclipse.mdm.api.dflt.model.Pool;
import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.dflt.model.ProjectDomain;
+import org.eclipse.mdm.api.dflt.model.Status;
import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
import org.eclipse.mdm.api.dflt.model.TemplateComponent;
import org.eclipse.mdm.api.dflt.model.TemplateRoot;
@@ -498,8 +499,27 @@
entityConfigRepository.register(create(new Key<>(Pool.class), "StructureLevel", true));
entityConfigRepository.register(create(new Key<>(PhysicalDimension.class), "PhysDimension", false));
entityConfigRepository.register(create(new Key<>(User.class), "User", false));
- entityConfigRepository.register(create(new Key<>(Measurement.class), "MeaResult", false));
entityConfigRepository.register(create(new Key<>(ChannelGroup.class), "SubMatrix", false));
+ entityConfigRepository.register(create(new Key<>(Status.class), "Status", true));
+
+ // Project Domain
+ EntityConfig<ProjectDomain> projectDomainEntityConfig = create(new Key<>(ProjectDomain.class), "ProjectDomain", true);
+ entityConfigRepository.register(projectDomainEntityConfig);
+
+ // Domain
+ EntityConfig<Domain> domainEntityConfig = create(new Key<>(Domain.class), "Domain", true);
+ entityConfigRepository.register(domainEntityConfig);
+
+ // Classification
+ EntityConfig<Classification> classificationEntityConfig = create(new Key<>(Classification.class), "Classification", true);
+ classificationEntityConfig.addOptional(entityConfigRepository.findRoot(new Key<>(ProjectDomain.class)));
+ classificationEntityConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Domain.class)));
+ classificationEntityConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Status.class)));
+ entityConfigRepository.register(classificationEntityConfig);
+
+ EntityConfig<Measurement> measurementEntityConfig = create(new Key<>(Measurement.class), "MeaResult", false);
+ measurementEntityConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Classification.class)));
+ entityConfigRepository.register(measurementEntityConfig);
// Unit
EntityConfig<Unit> unitConfig = create(new Key<>(Unit.class), "Unit", false);