| /********************************************************************************
|
| * 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.freetextindexer.boundary; |
| |
| import java.security.Principal; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.function.Consumer; |
| import java.util.function.Function; |
| import java.util.stream.Collectors; |
| |
| import javax.annotation.PostConstruct; |
| import javax.annotation.PreDestroy; |
| import javax.ejb.Startup; |
| import javax.ejb.Stateful; |
| import javax.ejb.TransactionAttribute; |
| import javax.ejb.TransactionAttributeType; |
| import javax.inject.Inject; |
| |
| import org.eclipse.mdm.api.base.ConnectionException; |
| import org.eclipse.mdm.api.base.ServiceNotProvidedException; |
| import org.eclipse.mdm.api.base.adapter.EntityType; |
| import org.eclipse.mdm.api.base.model.Entity; |
| 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.NotificationListener; |
| import org.eclipse.mdm.api.base.notification.NotificationService; |
| import org.eclipse.mdm.api.base.query.DataAccessException; |
| import org.eclipse.mdm.api.dflt.ApplicationContext; |
| import org.eclipse.mdm.api.dflt.EntityManager; |
| import org.eclipse.mdm.connector.boundary.ConnectorService; |
| import org.eclipse.mdm.freetextindexer.control.UpdateIndex; |
| import org.eclipse.mdm.freetextindexer.entities.MDMEntityResponse; |
| import org.eclipse.mdm.property.GlobalProperty; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * This boundary is a back-end Boundary to the openMDM Api. It uses the Seach |
| * Server to build up MDDocuments. |
| * |
| * @author CWE |
| * |
| */ |
| @TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED) |
| @Startup |
| @Stateful |
| public class MdmApiBoundary { |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(MdmApiBoundary.class); |
| |
| private static final String FREETEXT_NOTIFICATION_NAME = "freetext.notificationName"; |
| |
| public class FreeTextNotificationListener implements NotificationListener { |
| |
| private EntityManager entityManager; |
| |
| public FreeTextNotificationListener(EntityManager entityManager) { |
| this.entityManager = entityManager; |
| } |
| |
| @Override |
| public void instanceCreated(List<? extends Entity> entities, User arg1) { |
| LOGGER.debug("{} entities created: {}", entities.size(), entities); |
| entities.forEach(e -> update.change(MDMEntityResponse.build(e.getClass(), e, entityManager))); |
| } |
| |
| @Override |
| public void instanceDeleted(EntityType entityType, List<String> ids, User user) { |
| LOGGER.debug("{} entities deleted: {}", ids.size(), ids); |
| ids.forEach(id -> update.delete(getApiName(entityManager), workaroundForTypeMapping(entityType), id)); |
| } |
| |
| @Override |
| public void instanceModified(List<? extends Entity> entities, User arg1) { |
| LOGGER.debug("{} entities modified: {}", entities.size(), entities); |
| entities.forEach(e -> update.change(MDMEntityResponse.build(e.getClass(), e, entityManager))); |
| } |
| |
| @Override |
| public void modelModified(EntityType arg0, User arg1) { |
| // not needed |
| } |
| |
| @Override |
| public void securityModified(EntityType entityType, List<String> ids, User user) { |
| // not needed |
| } |
| } |
| |
| @Inject |
| ConnectorService service; |
| |
| @Inject |
| UpdateIndex update; |
| |
| @Inject |
| @GlobalProperty(value = "freetext.active") |
| private String active = "false"; |
| |
| ConnectorService connectorService; |
| |
| @Inject |
| @GlobalProperty |
| private Map<String, String> globalProperties = Collections.emptyMap(); |
| |
| @PostConstruct |
| public void initalize() { |
| Principal principal = new Principal() { |
| |
| @Override |
| public String getName() { |
| return null; |
| } |
| }; |
| |
| connectorService = new ConnectorService(principal, globalProperties); |
| connectorService.connect(); |
| connectorService.getContexts().forEach(this::initializeContext); |
| } |
| |
| private void initializeContext(ApplicationContext context) { |
| |
| String source = getName(context); |
| |
| try { |
| EntityManager entityManager = context.getEntityManager() |
| .orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class)); |
| |
| NotificationService manager = context.getNotificationService() |
| .orElseThrow(() -> new ConnectionException("Context has no NotificationManager!")); |
| |
| String notificationName = context.getParameters().getOrDefault(FREETEXT_NOTIFICATION_NAME, "mdm5"); |
| LOGGER.debug("Registering with name '{}' at source '{}'", notificationName, source); |
| |
| manager.register(notificationName, new NotificationFilter(), new FreeTextNotificationListener(entityManager)); |
| LOGGER.info("Successfully registered for new notifications with name '{}' at source '{}!", notificationName, source); |
| } catch (ConnectionException | NotificationException e) { |
| throw new IllegalArgumentException("The ODS Server and/or the Notification Service cannot be accessed for source '" + source + "'!", |
| e); |
| } |
| } |
| |
| @PreDestroy |
| public void deregister() { |
| for (ApplicationContext context : getContexts().values()) { |
| try { |
| context.getNotificationService() |
| .orElseThrow(() -> new ConnectionException("Context has no NotificationManager!")) |
| .close(false); |
| |
| } catch (ConnectionException | NotificationException e) { |
| throw new IllegalStateException( |
| "The NotificationManager could not be deregistered. In rare cases, this leads to a missed notification. This means the index might not be up-to-date."); |
| } |
| } |
| |
| connectorService.disconnect(); |
| } |
| |
| public void doForAllEntities(Class<? extends Entity> entityClass, ApplicationContext context, Consumer<? super MDMEntityResponse> executor) { |
| if (isActive()) { |
| try { |
| EntityManager entityManager = context.getEntityManager() |
| .orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class)); |
| |
| entityManager.loadAll(entityClass).stream().map(e -> this.buildEntity(e, entityManager)).forEach(executor); |
| |
| } catch (DataAccessException e) { |
| throw new IllegalStateException("MDM cannot be querried for new elements. Please check the MDM runtime", e); |
| } |
| } |
| } |
| |
| public Map<String, ApplicationContext> getContexts() { |
| return connectorService.getContexts().stream().collect(Collectors.toMap(this::getName, Function.identity())); |
| } |
| |
| public String getName(ApplicationContext context) { |
| return context.getEntityManager() |
| .map(this::getApiName) |
| .orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class)); |
| } |
| |
| private String getApiName(EntityManager entityManager) { |
| return entityManager.loadEnvironment().getSourceName(); |
| } |
| |
| private boolean isActive() { |
| return Boolean.parseBoolean(active) && !getContexts().isEmpty(); |
| } |
| |
| private MDMEntityResponse buildEntity(Entity e, EntityManager entityManager) { |
| return MDMEntityResponse.build(e.getClass(), e, entityManager); |
| } |
| |
| /** |
| * Simple workaround for naming mismatch between Adapter and Business object |
| * names. |
| * |
| * @param entityType |
| * entity type |
| * @return MDM business object name |
| */ |
| private static String workaroundForTypeMapping(EntityType entityType) { |
| switch (entityType.getName()) { |
| case "StructureLevel": |
| return "Pool"; |
| case "MeaResult": |
| return "Measurement"; |
| case "SubMatrix": |
| return "ChannelGroup"; |
| case "MeaQuantity": |
| return "Channel"; |
| default: |
| return entityType.getName(); |
| } |
| } |
| } |