blob: 4d9b6fd19f452e9892c99b15eb3d68aca536dc31 [file] [log] [blame]
/********************************************************************************
* 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.apicopy.boundary;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.management.ServiceNotFoundException;
import org.eclipse.mdm.api.base.ConnectionException;
import org.eclipse.mdm.api.base.model.Channel;
import org.eclipse.mdm.api.base.model.ChannelGroup;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.Test;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.dflt.ApplicationContext;
import org.eclipse.mdm.api.dflt.ApplicationContextFactory;
import org.eclipse.mdm.api.dflt.EntityManager;
import org.eclipse.mdm.api.dflt.model.Pool;
import org.eclipse.mdm.api.dflt.model.Project;
import org.eclipse.mdm.apicopy.ApiCopyException;
import org.eclipse.mdm.apicopy.AtfxExportTask;
import org.eclipse.mdm.connector.boundary.ConnectorService;
import org.eclipse.mdm.shoppingbasket.entity.MDMItem;
import org.eclipse.mdm.shoppingbasket.entity.ShoppingBasket;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
/**
* Service for importing an ATFX file into a MDM datasource.
*
*/
@Stateless
public class ExportService {
// TODO make temp path configurable
private static final Path TMP = Paths.get(System.getProperty("java.io.tmpdir"));
@Inject
private ConnectorService connectorService;
private final String atfxContextFactoryClassname = "org.eclipse.mdm.api.atfxadapter.ATFXContextFactory";
/**
* Default public constructor
*/
public ExportService() {
}
/**
* Imports an ATFX file into the provided datasource.
*
* @param atfxFileSupplier returns a {@link Path} to an ATFX file. Accompanying binary
* files are expected to be on the same folder.
* @return
*/
public Path exportAtfx(ShoppingBasket basket) {
try {
Path tmpDir = Files.createTempDirectory(TMP, "atfxexport");
Path atfxFile = tmpDir.resolve("export.atfx");
writeToFile(atfxFile, AtfxExportTask.class.getResourceAsStream("/emptyAtfx.xml"));
Map<String, String> params = ImmutableMap.of("atfxfile", atfxFile.toFile().getAbsolutePath(), "freetext.active", "false");
ApplicationContext contextDst = connectContext(atfxContextFactoryClassname, params);
Map<String, List<MDMItem>> map = basket.getItems().stream()
.map(i -> i.getRestURI().getPath())
.map(p -> split(p))
.collect(Collectors.groupingBy(p -> p.getSource()));
if (map.size() != 1) {
throw new ApiCopyException("Currently only exports from exactly one application context are allowed!");
}
String srcContextName = map.keySet().iterator().next();
ApplicationContext contextSrc = connectorService.getContextByName(srcContextName);
List<? extends Entity> entities = loadEntities(contextSrc, basket);
new AtfxExportTask(contextSrc, contextDst).copy(entities);
// apiCopyService.newApiCopyTask(contextSrc, contextDst).copy(entities);
return tmpDir;
} catch (ServiceNotFoundException e) {
throw new ApiCopyException("Could not retrive all required services from ATFX application context!", e);
} catch (ConnectionException e) {
throw new ApiCopyException("Could not create ATFX application context!", e);
} catch (IOException e) {
throw new ApiCopyException("Cold not create temporary directory!", e);
}
}
private List<? extends Entity> loadEntities(ApplicationContext contextSrc, ShoppingBasket basket) throws ServiceNotFoundException, DataAccessException {
EntityManager em = contextSrc.getEntityManager()
.orElseThrow(() -> new ServiceNotFoundException("EntityManager not found!"));
return basket.getItems().stream()
.map(i -> i.getRestURI().getPath())
.map(p -> split(p))
.map(i -> em.load(typeToClass(i.getType()), i.getId()))
.collect(Collectors.toList());
}
private Class<? extends Entity> typeToClass(String s) {
return ENTITY2FRAGMENT_URI.inverse().get(s);
}
private static final BiMap<Class<? extends Entity>, String> ENTITY2FRAGMENT_URI = ImmutableBiMap
.<Class<? extends Entity>, String>builder()
.put(Project.class, "projects")
.put(Pool.class, "pools")
.put(Test.class, "tests")
.put(TestStep.class, "teststeps")
.put(Measurement.class, "measurements")
.put(ChannelGroup.class, "channelgroups")
.put(Channel.class, "channels")
.build();
private MDMItem split(String path) {
String[] splitted = path.split("/");
MDMItem item = new MDMItem();
item.setId(splitted[splitted.length - 1]);
item.setType(splitted[splitted.length - 2]);
item.setSource(splitted[splitted.length - 3]);
return item;
}
/**
* Connects to a {@link ApplicationContext}.
* @param contextFactoryClassname classname of the {@link ApplicationContextFactory}
* @param parameters connection parameters
* @return connected {@link ApplicationContext}
* @throws ConnectionException
*/
private ApplicationContext connectContext(String contextFactoryClassname, Map<String, String> parameters) throws ConnectionException {
try {
Class<? extends ApplicationContextFactory> contextFactoryClass = Thread.currentThread()
.getContextClassLoader().loadClass(contextFactoryClassname)
.asSubclass(ApplicationContextFactory.class);
ApplicationContextFactory contextFactory = contextFactoryClass.newInstance();
return contextFactory.connect(parameters);
} catch (Exception e) {
throw new ConnectionException("failed to initialize entity manager using factory '" + contextFactoryClassname + "'", e);
}
}
private static void writeToFile(Path resolve, InputStream entityAs) throws IOException {
try (OutputStream out = new FileOutputStream(resolve.toFile())) {
int read = 0;
byte[] bytes = new byte[1024];
while ((read = entityAs.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
}
}
}