Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package net.firejack.platform.api.registry.broker; import net.firejack.platform.api.OPFEngine; import net.firejack.platform.api.registry.domain.*; import net.firejack.platform.api.registry.field.Field; import net.firejack.platform.api.registry.model.BIReportLocation; import net.firejack.platform.core.broker.ServiceBroker; import net.firejack.platform.core.domain.NamedValues; import net.firejack.platform.core.request.ServiceRequest; import net.firejack.platform.core.response.ServiceResponse; import net.firejack.platform.core.store.IAbstractStore; import net.firejack.platform.core.utils.*; import net.firejack.platform.utils.WebUtils; import net.firejack.platform.utils.generate.FormattingUtils; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import java.beans.PropertyDescriptor; import java.util.*; public class ReadBaseBIReportDataBroker extends ServiceBroker<ServiceRequest<NamedValues>, ServiceResponse<BIReportData>> { @Override protected ServiceResponse<BIReportData> perform(ServiceRequest<NamedValues> request) throws Exception { Long biReportUserId = (Long) request.getData().get("id"); String parentNodeValues = (String) request.getData().get("parentNodeValues"); String[] parentRowValues = WebUtils.deserializeJSON(parentNodeValues, String[].class); int depth = parentRowValues.length; ServiceResponse<BIReportData> response; ServiceResponse<BIReportUser> biReportUserResponse = OPFEngine.RegistryService .readBIReportUser(biReportUserId); if (biReportUserResponse.isSuccess()) { BIReportData biReport = new BIReportData(); BIReportUser biReportUser = biReportUserResponse.getItem(); List<BIReportUserField> biReportUserFields = biReportUser.getFields(); Map<Long, BIReportField> entityBIReportFieldMap = new HashMap<Long, BIReportField>(); for (BIReportField biReportField : biReportUser.getReport().getFields()) { if (biReportField.getField() == null) { entityBIReportFieldMap.put(biReportField.getEntity().getId(), biReportField); } } Integer columnIndex = 0; List<BIReportColumn> biReportColumns = new ArrayList<BIReportColumn>(); Map<BIReportField, BIReportLocation> groupedBIReportFields = new LinkedHashMap<BIReportField, BIReportLocation>(); Map<Integer, BIReportRow> verticalColumnsMapping = new HashMap<Integer, BIReportRow>(); List<BIReportUserField> verticalBIReportUserFields = getFieldsByLocation(biReportUserFields, BIReportLocation.VERTICAL); Entity previousEntity = null; for (int i = 0; i < verticalBIReportUserFields.size(); i++) { BIReportUserField biReportUserField = verticalBIReportUserFields.get(i); BIReportField biReportField = biReportUserField.getField(); Entity entity = biReportField.getEntity(); if (previousEntity == null || !previousEntity.getId().equals(entity.getId())) { String columnName = entity.getName(); BIReportField entityBIReportField = entityBIReportFieldMap.get(entity.getId()); if (entityBIReportField != null) { columnName = StringUtils.defaultIfEmpty(entityBIReportField.getDisplayName(), columnName); } BIReportColumn biReportColumn = new BIReportColumn(); biReportColumn.setName(columnName); biReportColumn.setType(BIReportLocation.VERTICAL); biReportColumn.setColumnIndex(columnIndex); biReportColumn.setExpanded(biReportUserField.isExpanded()); biReportColumn.setUnShift(i); biReportColumns.add(biReportColumn); columnIndex++; previousEntity = entity; } BIReportRow biReportRow = new BIReportRow(); biReportRow.setColumnIndex(biReportColumns.size() - 1); biReportRow.setExpanded(biReportUserField.isExpanded()); verticalColumnsMapping.put(i, biReportRow); groupedBIReportFields.put(biReportField, BIReportLocation.VERTICAL); } biReport.setCountOfLevels(verticalColumnsMapping.size()); List<BIReportUserField> horizontalBIReportUserFields = getFieldsByLocation(biReportUserFields, BIReportLocation.HORIZONTAL); Map<Entity, List<BIReportField>> entityBIReportFields = new LinkedHashMap<Entity, List<BIReportField>>(); for (BIReportUserField biReportUserField : horizontalBIReportUserFields) { BIReportField biReportField = biReportUserField.getField(); Entity entity = biReportField.getEntity(); List<BIReportField> biReportFields = entityBIReportFields.get(entity); if (biReportFields == null) { biReportFields = new ArrayList<BIReportField>(); entityBIReportFields.put(entity, biReportFields); } biReportFields.add(biReportField); groupedBIReportFields.put(biReportField, BIReportLocation.HORIZONTAL); } List<BIReportUserField> measureBIReportUserFields = getFieldsByLocation(biReportUserFields, BIReportLocation.MEASURE); for (BIReportUserField biReportUserField : measureBIReportUserFields) { BIReportField biReportField = biReportUserField.getField(); groupedBIReportFields.put(biReportField, BIReportLocation.MEASURE); } String biReportUserFilter = biReportUser.getFilter(); biReport.setFilter(biReportUserFilter); List<List<SearchQuery>> filterSearchQueries = WebUtils.deserializeJSON(biReportUserFilter, List.class, List.class, SearchQuery.class); BIReportUserField measureBIReportUserField = measureBIReportUserFields.get(0); BIReportField measureBIReportField = measureBIReportUserField.getField(); Entity factEntity = measureBIReportField.getEntity(); String factDomainClassName = FormattingUtils.classFormatting(factEntity.getName()); String factModelClassName = factEntity.getPath() + ".model." + factDomainClassName + "Model"; Class<?> factModelClass = Class.forName(factModelClassName); List<Object[]> globalList = null; for (Map.Entry<Entity, List<BIReportField>> entry : entityBIReportFields.entrySet()) { Entity entity = entry.getKey(); List<BIReportField> biReportFields = entry.getValue(); String domainClassName = FormattingUtils.classFormatting(entity.getName()); String modelClassName = entity.getPath() + ".model." + domainClassName + "Model"; String storeClassName = entity.getPath() + ".store.Basic" + domainClassName + "Store"; IAbstractStore store = OpenFlameSpringContext.getBean(storeClassName); List<List<SearchQuery>> columnSearchQueryList = new ArrayList<List<SearchQuery>>(); List<SortField> sortFields = new ArrayList<SortField>(); ProjectionList projectionList = Projections.projectionList(); for (BIReportField biReportField : biReportFields) { Field field = biReportField.getField(); String fieldName = FormattingUtils.fieldModelFormatting(field.getName()); projectionList.add(Projections.property(fieldName)); sortFields.add(new SortField(fieldName, SortOrder.ASC)); String fkDimFieldName = findDimFieldName(factModelClass, modelClassName); for (List<SearchQuery> searchQueries : filterSearchQueries) { List<SearchQuery> columnSearchQueries = new ArrayList<SearchQuery>(); for (SearchQuery searchQuery : searchQueries) { String searchField = searchQuery.getField(); String[] fieldNames = searchField.split("\\."); if (fieldNames.length == 2 && fieldNames[0].equals(fkDimFieldName)) { SearchQuery columnSearchQuery = new SearchQuery(fieldNames[1], searchQuery.getOperation(), searchQuery.getValue()); columnSearchQueries.add(columnSearchQuery); } } if (columnSearchQueries.isEmpty()) { SearchQuery alwaysTrueSearchQuery = new SearchQuery(); columnSearchQueries.add(alwaysTrueSearchQuery); } columnSearchQueryList.add(columnSearchQueries); } } Paging paging = new Paging(null, null, sortFields); List<Object[]> objectsList; if (biReportFields.size() > 1) { objectsList = store.advancedSearchWithProjection(columnSearchQueryList, Projections.distinct(projectionList), null, paging); } else { objectsList = new ArrayList<Object[]>(); List<Object> objectList = store.advancedSearchWithProjection(columnSearchQueryList, Projections.distinct(projectionList), null, paging); for (Object object : objectList) { objectsList.add(new Object[] { object }); } } if (globalList == null) { globalList = objectsList; } else { List<Object[]> mergedList = new ArrayList<Object[]>(); for (Object[] globalObjects : globalList) { for (Object[] objects : objectsList) { Object[] mergedObjects = ArrayUtils.addAll(globalObjects, objects); mergedList.add(mergedObjects); } } globalList = mergedList; } } List<BIReportField> measureBIReportFields = getFieldsByLocation(groupedBIReportFields, BIReportLocation.MEASURE); Map<ArrayKey, Integer> horizontalColumnMapping = generateHorizontalColumns(globalList, biReportColumns, measureBIReportFields, columnIndex); if (depth == 0) { biReport.setColumns(biReportColumns); } int countOfExpandedChildren = 1; int countOfVerticalColumns = verticalColumnsMapping.size(); for (int i = depth; i < countOfVerticalColumns; i++) { BIReportRow verticalBIReportRow = verticalColumnsMapping.get(i); if (verticalBIReportRow.isExpanded()) { countOfExpandedChildren++; } else { break; } } ProjectionList projectionList = Projections.projectionList(); List<SortField> sortFields = new ArrayList<SortField>(); Map<String, String> aliases = new HashMap<String, String>(); int positionOfLastExpandedColumns = depth + countOfExpandedChildren - 1; List<SearchQuery> childrenFilterSearchQueries = new ArrayList<SearchQuery>(); List<BIReportField> verticalBIReportFields = getFieldsByLocation(groupedBIReportFields, new BIReportLocation[] { BIReportLocation.VERTICAL }); for (int i = 0; i < verticalBIReportFields.size(); i++) { BIReportField biReportField = verticalBIReportFields.get(i); Entity dimEntity = biReportField.getEntity(); String dimDomainClassName = FormattingUtils.classFormatting(dimEntity.getName()); String dimModelClassName = dimEntity.getPath() + ".model." + dimDomainClassName + "Model"; String fkDimFieldName = findDimFieldName(factModelClass, dimModelClassName); aliases.put(fkDimFieldName, fkDimFieldName); Field field = biReportField.getField(); String fieldName = FormattingUtils.fieldModelFormatting(field.getName()); String aliasedFieldName = fkDimFieldName + "." + fieldName; projectionList.add(Projections.groupProperty(aliasedFieldName)); sortFields.add(new SortField(aliasedFieldName, SortOrder.ASC)); if (positionOfLastExpandedColumns >= i + 1) { if (depth >= i + 1) { SearchQuery searchQuery = new SearchQuery(); searchQuery.setField(aliasedFieldName); searchQuery.setOperation(QueryOperation.EQUALS); searchQuery.setValue(parentRowValues[i]); childrenFilterSearchQueries.add(searchQuery); } } else { break; } } if (filterSearchQueries.isEmpty()) { filterSearchQueries.add(childrenFilterSearchQueries); } else { for (List<SearchQuery> searchQueries : filterSearchQueries) { for (SearchQuery childrenFilterSearchQuery : childrenFilterSearchQueries) { searchQueries.add(childrenFilterSearchQuery); } } } List<BIReportField> horizontalBIReportFields = getFieldsByLocation(groupedBIReportFields, new BIReportLocation[] { BIReportLocation.HORIZONTAL }); for (BIReportField biReportField : horizontalBIReportFields) { Entity dimEntity = biReportField.getEntity(); String dimDomainClassName = FormattingUtils.classFormatting(dimEntity.getName()); String dimModelClassName = dimEntity.getPath() + ".model." + dimDomainClassName + "Model"; String fkDimFieldName = findDimFieldName(factModelClass, dimModelClassName); aliases.put(fkDimFieldName, fkDimFieldName); Field field = biReportField.getField(); String fieldName = FormattingUtils.fieldModelFormatting(field.getName()); String aliasedFieldName = fkDimFieldName + "." + fieldName; projectionList.add(Projections.groupProperty(aliasedFieldName)); sortFields.add(new SortField(aliasedFieldName, SortOrder.ASC)); } for (BIReportField biReportField : measureBIReportFields) { Field field = biReportField.getField(); String fieldName = FormattingUtils.fieldModelFormatting(field.getName()); projectionList.add(Projections.count(fieldName)); } String storeClassName = factEntity.getPath() + ".store.Basic" + factDomainClassName + "Store"; IAbstractStore store = OpenFlameSpringContext.getBean(storeClassName); List<Object[]> dataList = store.advancedSearchWithProjection(filterSearchQueries, Projections.distinct(projectionList), aliases, new Paging(null, null, sortFields)); int countOfHorizontalColumns = horizontalBIReportUserFields.size(); int countOfMeasureColumns = measureBIReportUserFields.size(); List<BIReportRow> biReportRows = generateRows(dataList, verticalColumnsMapping, horizontalColumnMapping, countOfVerticalColumns, countOfHorizontalColumns, countOfMeasureColumns, depth, countOfExpandedChildren); biReport.setRows(biReportRows); response = new ServiceResponse<BIReportData>(biReport, "BI Report data", true); } else { response = new ServiceResponse<BIReportData>( "Could not find user configuration of BIReport by ID: " + biReportUserId, false); } return response; } protected List<BIReportUserField> getFieldsByLocation(List<BIReportUserField> fields, BIReportLocation location) { List<BIReportUserField> locationFields = new ArrayList<BIReportUserField>(); for (BIReportUserField biReportUserField : fields) { if (location.equals(biReportUserField.getLocation())) { locationFields.add(biReportUserField); } } Collections.sort(locationFields, new Comparator<BIReportUserField>() { @Override public int compare(BIReportUserField field1, BIReportUserField field2) { return field1.getOrder() - field2.getOrder(); } }); return locationFields; } protected List<BIReportField> getFieldsByLocation(Map<BIReportField, BIReportLocation> biReportFields, BIReportLocation[] locations) { List<BIReportField> locationFields = new ArrayList<BIReportField>(); for (BIReportLocation location : locations) { locationFields.addAll(getFieldsByLocation(biReportFields, location)); } return locationFields; } protected List<BIReportField> getFieldsByLocation(Map<BIReportField, BIReportLocation> biReportFields, BIReportLocation location) { List<BIReportField> locationFields = new ArrayList<BIReportField>(); for (Map.Entry<BIReportField, BIReportLocation> entry : biReportFields.entrySet()) { BIReportLocation biReportLocation = entry.getValue(); if (location.equals(biReportLocation)) { locationFields.add(entry.getKey()); } } return locationFields; } protected Map<ArrayKey, Integer> generateHorizontalColumns(List<Object[]> list, List<BIReportColumn> biReportColumns, List<BIReportField> measureBIReportFields, Integer columnIndex) { Map<String, Map> mapColumns = new LinkedHashMap<String, Map>(); for (Object[] objects : list) { buildMapColumns(objects, 0, mapColumns); } Map<ArrayKey, Integer> horizontalColumnMapping = new HashMap<ArrayKey, Integer>(); generateHorizontalColumns(mapColumns, biReportColumns, measureBIReportFields, new Integer[] { columnIndex }, new String[] {}, horizontalColumnMapping); return horizontalColumnMapping; } protected void buildMapColumns(Object[] objects, int i, Map<String, Map> mapColumns) { Object object = objects[i]; String name = String.valueOf(object); Map<String, Map> childrenMapColumns = mapColumns.get(name); if (childrenMapColumns == null) { childrenMapColumns = new LinkedHashMap<String, Map>(); mapColumns.put(name, childrenMapColumns); } if (objects.length > (i + 1)) { buildMapColumns(objects, ++i, childrenMapColumns); } } protected void generateHorizontalColumns(Map<String, Map> mapColumns, List<BIReportColumn> biReportColumns, List<BIReportField> measureBIReportFields, Integer[] columnIndex, String[] columnPaths, Map<ArrayKey, Integer> horizontalColumnMapping) { for (Map.Entry<String, Map> entry : mapColumns.entrySet()) { String name = entry.getKey(); BIReportColumn biReportColumn = new BIReportColumn(); biReportColumn.setName(name); biReportColumn.setType(BIReportLocation.HORIZONTAL); columnPaths = (String[]) ArrayUtils.add(columnPaths, name); List<BIReportColumn> childrenBIReportColumns = biReportColumn.getChildren(); if (childrenBIReportColumns == null) { childrenBIReportColumns = new ArrayList<BIReportColumn>(); biReportColumn.setChildren(childrenBIReportColumns); } Map<String, Map> childrenMapColumns = entry.getValue(); if (!childrenMapColumns.isEmpty()) { generateHorizontalColumns(childrenMapColumns, childrenBIReportColumns, measureBIReportFields, columnIndex, columnPaths, horizontalColumnMapping); } else { columnIndex = generateMeasureColumns(childrenBIReportColumns, measureBIReportFields, columnIndex, columnPaths, horizontalColumnMapping); } columnPaths = (String[]) ArrayUtils.remove(columnPaths, columnPaths.length - 1); biReportColumns.add(biReportColumn); } } protected Integer[] generateMeasureColumns(List<BIReportColumn> childrenBIReportColumns, List<BIReportField> measureBIReportFields, Integer[] columnIndex, String[] columnPaths, Map<ArrayKey, Integer> horizontalColumnMapping) { for (int i = 0; i < measureBIReportFields.size(); i++) { BIReportField biReportField = measureBIReportFields.get(i); BIReportColumn biReportColumnMeasure = new BIReportColumn(); biReportColumnMeasure.setName(biReportField.getDisplayName()); biReportColumnMeasure.setType(BIReportLocation.MEASURE); biReportColumnMeasure.setColumnIndex(columnIndex[0]); childrenBIReportColumns.add(biReportColumnMeasure); columnPaths = (String[]) ArrayUtils.add(columnPaths, String.valueOf(i)); horizontalColumnMapping.put(new ArrayKey((String[]) ArrayUtils.clone(columnPaths)), columnIndex[0]); columnPaths = (String[]) ArrayUtils.remove(columnPaths, columnPaths.length - 1); columnIndex[0]++; } return columnIndex; } protected List<BIReportRow> generateRows(List<Object[]> dataList, Map<Integer, BIReportRow> verticalColumnsMapping, Map<ArrayKey, Integer> horizontalColumnMapping, int countOfVerticalColumns, int countOfHorizontalColumns, int countOfMeasureColumns, int depth, int countExpandedColumns) { Map<String, BIReportRow> rootBIReportRowsMap = new LinkedHashMap<String, BIReportRow>(); for (Object[] data : dataList) { int countOfVerticalDataColumns = depth + countExpandedColumns; int countOfAdditionalEmptyColumns = countOfVerticalColumns - countOfVerticalDataColumns; for (int i = 0; i < countOfAdditionalEmptyColumns; i++) { data = ArrayUtils.add(data, countOfVerticalDataColumns, ""); } Map<String, BIReportRow> biReportRowsMap = rootBIReportRowsMap; for (int i = depth; i < countOfVerticalDataColumns; i++) { Object object = data[i]; boolean isNullValue = object == null; String verticalRowValue = String.valueOf(object); BIReportRow biReportRow = biReportRowsMap.get(verticalRowValue); BIReportRow verticalBIReportRow = verticalColumnsMapping.get(i); Integer columnIndex = verticalBIReportRow.getColumnIndex(); if (biReportRow == null) { biReportRow = new BIReportRow(); biReportRow.setName(verticalRowValue); biReportRow.setColumnIndex(columnIndex); biReportRow.setExpanded(verticalBIReportRow.isExpanded()); biReportRow.setLeaf(countOfVerticalColumns == i + 1 || isNullValue); biReportRow.setDepth(i + 1); biReportRow.setBiReportRowMap(new LinkedHashMap<String, BIReportRow>()); biReportRowsMap.put(verticalRowValue, biReportRow); } if (countOfVerticalDataColumns == i + 1) { Map<Integer, Double> columnIndexValues = biReportRow.getColumnIndexValues(); if (columnIndexValues == null) { columnIndexValues = new HashMap<Integer, Double>(); biReportRow.setColumnIndexValues(columnIndexValues); } Object[] keyValues = ArrayUtils.subarray(data, countOfVerticalColumns, countOfVerticalColumns + countOfHorizontalColumns); for (int m = 0; m < countOfMeasureColumns; m++) { keyValues = ArrayUtils.add(keyValues, String.valueOf(m)); columnIndex = horizontalColumnMapping.get(new ArrayKey(keyValues)); Double dataValue = Double.valueOf(String.valueOf( ArrayUtils.subarray(data, countOfVerticalColumns + countOfHorizontalColumns + m, countOfVerticalColumns + countOfHorizontalColumns + m + 1)[0])); Double cellValue = columnIndexValues.get(columnIndex); if (cellValue == null) { columnIndexValues.put(columnIndex, dataValue); } else { columnIndexValues.put(columnIndex, cellValue + dataValue); } } } biReportRowsMap = biReportRow.getBiReportRowMap(); } } ArrayList<BIReportRow> biReportRows = new ArrayList<BIReportRow>(rootBIReportRowsMap.values()); calculateRowTotals(null, biReportRows); return biReportRows; } protected void calculateRowTotals(BIReportRow parentBIReportRow, List<BIReportRow> biReportRows) { Map<Integer, Double> columnIndexTotalValues = new HashMap<Integer, Double>(); for (BIReportRow biReportRow : biReportRows) { List<BIReportRow> childrenBIReportRow = biReportRow.getChildren(); calculateRowTotals(biReportRow, childrenBIReportRow); Map<Integer, Double> columnIndexValues = biReportRow.getColumnIndexValues(); for (Map.Entry<Integer, Double> entry : columnIndexValues.entrySet()) { Double columnIndexTotalValue = columnIndexTotalValues.get(entry.getKey()); if (columnIndexTotalValue == null) { columnIndexTotalValues.put(entry.getKey(), entry.getValue()); } else { columnIndexTotalValues.put(entry.getKey(), columnIndexTotalValue + entry.getValue()); } } if (parentBIReportRow != null) { parentBIReportRow.setColumnIndexValues(columnIndexTotalValues); } } } protected String findDimFieldName(Class<?> factModelClass, String dimModelClassName) { String propertyName = null; PropertyDescriptor[] propertyDescriptors = ClassUtils.getPropertyDescriptors(factModelClass); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { if (propertyDescriptor.getReadMethod().getReturnType().getName().equals(dimModelClassName)) { propertyName = propertyDescriptor.getName(); break; } } return propertyName; } protected static final class ArrayKey { private final String[] keys; public ArrayKey(Object[] objects) { this.keys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { this.keys[i] = String.valueOf(objects[i]); } } public ArrayKey(String[] keys) { this.keys = keys; } @Override public int hashCode() { int hash = 7; hash = 23 * hash + Arrays.hashCode(this.keys); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ArrayKey other = (ArrayKey) obj; return Arrays.equals(this.keys, other.keys); } } }