package io.lumify.analystsNotebook; import com.google.inject.Inject; import com.google.inject.Singleton; import io.lumify.analystsNotebook.aggregateClassification.AggregateClassificationClient; import io.lumify.analystsNotebook.model.*; import io.lumify.core.config.Configuration; import io.lumify.core.formula.FormulaEvaluator; import io.lumify.core.model.artifactThumbnails.ArtifactThumbnailRepository; import io.lumify.core.model.ontology.OntologyRepository; import io.lumify.core.model.workspace.Workspace; import io.lumify.core.model.workspace.WorkspaceEntity; import io.lumify.core.model.workspace.WorkspaceRepository; import io.lumify.core.user.User; import io.lumify.core.util.LumifyLogger; import io.lumify.core.util.LumifyLoggerFactory; import org.securegraph.Authorizations; import org.securegraph.Edge; import org.securegraph.Graph; import org.securegraph.Vertex; import org.securegraph.util.LookAheadIterable; import java.util.*; import static org.securegraph.util.IterableUtils.toList; @Singleton public class AnalystsNotebookExporter { private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(AnalystsNotebookExporter.class); private final FormulaEvaluator formulaEvaluator; private final Graph graph; private final WorkspaceRepository workspaceRepository; private final OntologyRepository ontologyRepository; private final ArtifactThumbnailRepository artifactThumbnailRepository; private final AnalystsNotebookExportConfiguration analystsNotebookExportConfiguration; private final AggregateClassificationClient aggregateClassificationClient; @Inject public AnalystsNotebookExporter( Graph graph, WorkspaceRepository workspaceRepository, OntologyRepository ontologyRepository, ArtifactThumbnailRepository artifactThumbnailRepository, Configuration configuration, FormulaEvaluator formulaEvaluator ) { this.graph = graph; this.workspaceRepository = workspaceRepository; this.ontologyRepository = ontologyRepository; this.artifactThumbnailRepository = artifactThumbnailRepository; this.formulaEvaluator = formulaEvaluator; analystsNotebookExportConfiguration = new AnalystsNotebookExportConfiguration(); configuration.setConfigurables(analystsNotebookExportConfiguration, AnalystsNotebookExportConfiguration.CONFIGURATION_PREFIX); aggregateClassificationClient = new AggregateClassificationClient(configuration); } public Chart toChart(AnalystsNotebookVersion version, Workspace workspace, User user, Authorizations authorizations, Locale locale, String timeZone, String baseUrl) { LOGGER.debug("creating Chart from workspace %s for Analyst's Notebook version %s", workspace.getWorkspaceId(), version.toString()); List<WorkspaceEntity> workspaceEntities = workspaceRepository.findEntities(workspace, user); Iterable<String> vertexIds = getVisibleWorkspaceEntityIds(workspaceEntities); Iterable<Vertex> vertices = graph.getVertices(vertexIds, authorizations); Map<Vertex, WorkspaceEntity> vertexWorkspaceEntityMap = createVertexWorkspaceEntityMap(vertices, workspaceEntities); List<Edge> edges = toList(graph.getEdges(graph.findRelatedEdges(vertexIds, authorizations), authorizations)); Chart chart = new Chart(); chart.setAttributeClassCollection(createAttributeClassCollection(vertices)); chart.setLinkTypeCollection(getLinkTypes()); chart.setEntityTypeCollection(EntityType.createForVertices(vertices, ontologyRepository, version)); if (version.supports(AnalystsNotebookFeature.CUSTOM_IMAGE_COLLECTION) && analystsNotebookExportConfiguration.enableCustomImageCollection()) { chart.setCustomImageCollection(CustomImage.createForVertices(vertices, ontologyRepository)); } String classificationBanner = aggregateClassificationClient.getClassificationBanner(vertices); if (version.supports(AnalystsNotebookFeature.SUMMARY) && classificationBanner != null) { chart.setSummary(getSummary(classificationBanner)); } if (version.supports(AnalystsNotebookFeature.PRINT_SETTINGS) && classificationBanner != null) { chart.setPrintSettings(getPrintSettings()); } List<ChartItem> chartItems = new ArrayList<>(); LOGGER.debug("adding %d vertices", vertexWorkspaceEntityMap.size()); FormulaEvaluator.UserContext userContext = new FormulaEvaluator.UserContext(locale, timeZone, workspace.getWorkspaceId()); for (Map.Entry<Vertex, WorkspaceEntity> entry : vertexWorkspaceEntityMap.entrySet()) { ChartItem fromVertexAndWorkspaceEntity = ChartItem.createFromVertexAndWorkspaceEntity( version, entry.getKey(), entry.getValue(), ontologyRepository, artifactThumbnailRepository, formulaEvaluator, userContext, workspace.getWorkspaceId(), authorizations, user, baseUrl, analystsNotebookExportConfiguration ); chartItems.add(fromVertexAndWorkspaceEntity); } LOGGER.debug("adding %d edges", edges.size()); for (Edge edge : edges) { chartItems.add(ChartItem.createFromEdge(version, edge, ontologyRepository)); } if (classificationBanner != null) { int margin = 50; int[] minXYmaxXY = getMinXYmaxXY(workspaceEntities); int middleX = minXYmaxXY[0] + ((minXYmaxXY[2] - minXYmaxXY[0]) / 2); // center of items int headerY = minXYmaxXY[1] - margin; // possible negative value seems ok int footerY = minXYmaxXY[3] + margin; chartItems.add(ChartItem.createLabel(version, middleX, headerY, classificationBanner, classificationBanner, "class_header")); chartItems.add(ChartItem.createLabel(version, middleX, footerY, classificationBanner, classificationBanner, "class_footer")); } chart.setChartItemCollection(chartItems); return chart; } private List<AttributeClass> createAttributeClassCollection(Iterable<Vertex> vertices) { List<AttributeClass> attributeClasses = new ArrayList<>(); if (analystsNotebookExportConfiguration.includeProperties()) { attributeClasses.addAll(AttributeClass.createForVertices(vertices, ontologyRepository)); } if (analystsNotebookExportConfiguration.includeSubtitle()) { attributeClasses.add(new AttributeClass(AttributeClass.NAME_SUBTITLE, AttributeClass.TYPE_TEXT, true)); } if (analystsNotebookExportConfiguration.includeTime()) { attributeClasses.add(new AttributeClass(AttributeClass.NAME_TIME, AttributeClass.TYPE_TEXT, true)); } if (analystsNotebookExportConfiguration.includeImageUrl()) { attributeClasses.add(new AttributeClass(AttributeClass.NAME_IMAGE_URL, AttributeClass.TYPE_TEXT, false)); } if (analystsNotebookExportConfiguration.includeVisibility()) { String label = analystsNotebookExportConfiguration.getVisibilityLabel(); attributeClasses.add(new AttributeClass(label, AttributeClass.TYPE_TEXT, true)); } return attributeClasses; } private static Map<Vertex, WorkspaceEntity> createVertexWorkspaceEntityMap(Iterable<Vertex> vertices, List<WorkspaceEntity> workspaceEntities) { Map<Vertex, WorkspaceEntity> map = new HashMap<>(); for (Vertex vertex : vertices) { WorkspaceEntity correspondingWorkspaceEntity = null; for (WorkspaceEntity workspaceEntity : workspaceEntities) { if (workspaceEntity.getEntityVertexId().equals(vertex.getId())) { correspondingWorkspaceEntity = workspaceEntity; break; } } if (correspondingWorkspaceEntity != null) { map.put(vertex, correspondingWorkspaceEntity); } } return map; } private static int[] getMinXYmaxXY(Collection<WorkspaceEntity> workspaceEntities) { int[] minXYmaxXY = {Integer.MAX_VALUE, Integer.MAX_VALUE, 0, 0}; for (WorkspaceEntity workspaceEntity : workspaceEntities) { int x = workspaceEntity.getGraphPositionX(); int y = workspaceEntity.getGraphPositionY(); /* min x */ minXYmaxXY[0] = x < minXYmaxXY[0] ? x : minXYmaxXY[0]; /* min y */ minXYmaxXY[1] = y < minXYmaxXY[1] ? y : minXYmaxXY[1]; /* max x */ minXYmaxXY[2] = x > minXYmaxXY[2] ? x : minXYmaxXY[2]; /* max y */ minXYmaxXY[3] = y > minXYmaxXY[3] ? y : minXYmaxXY[3]; } return minXYmaxXY; } private static List<LinkType> getLinkTypes() { List<LinkType> linkTypes = new ArrayList<>(); LinkType linkType = new LinkType(); linkType.setColour("65280"); linkType.setName(LinkType.NAME_LINK); linkTypes.add(linkType); return linkTypes; } private static PrintSettings getPrintSettings() { PrintSettings printSettings = new PrintSettings(); List<Header> headers = new ArrayList<>(); Header header = new Header(); header.setPosition(Header.POSITION_HEADER_FOOTER_POSITION_CENTER); header.setProperty("classification"); header.setVisible(true); headers.add(header); printSettings.setHeaderCollection(headers); List<Footer> footers = new ArrayList<>(); Footer footer = new Footer(); footer.setPosition(Footer.POSITION_HEADER_FOOTER_POSITION_CENTER); footer.setProperty("classification"); footer.setVisible(true); footers.add(footer); printSettings.setFooterCollection(footers); return printSettings; } private static Summary getSummary(String classificationBanner) { Summary summary = new Summary(); List<CustomProperty> customProperties = new ArrayList<>(); CustomProperty customProperty = new CustomProperty(); customProperty.setName("classification"); customProperty.setType(CustomProperty.TYPE_STRING); customProperty.setValue(classificationBanner); customProperties.add(customProperty); summary.setCustomPropertyCollection(customProperties); return summary; } // TODO: this is copied from io.lumify.web.routes.workspace.WorkspaceVertices private LookAheadIterable<WorkspaceEntity, String> getVisibleWorkspaceEntityIds(final List<WorkspaceEntity> workspaceEntities) { return new LookAheadIterable<WorkspaceEntity, String>() { @Override protected boolean isIncluded(WorkspaceEntity workspaceEntity, String entityVertexId) { return workspaceEntity.isVisible(); } @Override protected String convert(WorkspaceEntity workspaceEntity) { return workspaceEntity.getEntityVertexId(); } @Override protected Iterator<WorkspaceEntity> createIterator() { return workspaceEntities.iterator(); } }; } }