Java tutorial
/* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.1 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2010-2014 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************ */ package org.openbravo.client.querylist; import java.math.BigDecimal; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.hibernate.Query; import org.hibernate.criterion.Restrictions; import org.openbravo.base.exception.OBException; import org.openbravo.base.exception.OBSecurityException; import org.openbravo.base.model.ModelProvider; import org.openbravo.base.model.domaintype.BigDecimalDomainType; import org.openbravo.base.model.domaintype.BooleanDomainType; import org.openbravo.base.model.domaintype.DateDomainType; import org.openbravo.base.model.domaintype.DomainType; import org.openbravo.base.model.domaintype.LongDomainType; import org.openbravo.base.model.domaintype.PrimitiveDomainType; import org.openbravo.client.application.Parameter; import org.openbravo.client.application.ParameterUtils; import org.openbravo.client.kernel.reference.EnumUIDefinition; import org.openbravo.client.kernel.reference.ForeignKeyUIDefinition; import org.openbravo.client.kernel.reference.NumberUIDefinition; import org.openbravo.client.kernel.reference.UIDefinition; import org.openbravo.client.kernel.reference.UIDefinitionController; import org.openbravo.client.kernel.reference.YesNoUIDefinition; import org.openbravo.client.myob.WidgetClass; import org.openbravo.client.myob.WidgetInstance; import org.openbravo.client.myob.WidgetReference; import org.openbravo.dal.core.OBContext; import org.openbravo.dal.service.OBCriteria; import org.openbravo.dal.service.OBDal; import org.openbravo.erpCommon.utility.OBMessageUtils; import org.openbravo.model.ad.access.WindowAccess; import org.openbravo.model.ad.datamodel.Column; import org.openbravo.model.ad.domain.Reference; import org.openbravo.model.ad.ui.Field; import org.openbravo.model.ad.ui.Window; import org.openbravo.portal.PortalAccessible; import org.openbravo.service.datasource.DataSourceProperty; import org.openbravo.service.datasource.ReadOnlyDataSourceService; import org.openbravo.service.json.AdvancedQueryBuilder; import org.openbravo.service.json.JsonConstants; import org.openbravo.service.json.JsonUtils; /** * Reads the tabs which the user is allowed to see. * * @author gorkaion */ public class QueryListDataSource extends ReadOnlyDataSourceService implements PortalAccessible { private static final String OPTIONAL_FILTERS = "@optional_filters@"; private static final Logger log = Logger.getLogger(QueryListDataSource.class); private static final String OPERATOR = "$OPERATOR"; /** * Returns the count of objects based on the passed parameters. * * @param parameters * the parameters passed in from the request * @return the total number of objects */ @Override protected int getCount(Map<String, String> parameters) { return getData(parameters, 0, -1).size(); } @Override protected List<Map<String, Object>> getData(Map<String, String> parameters, int startRow, int endRow) { // creation of formats is done here because they are not thread safe final SimpleDateFormat xmlDateFormat = JsonUtils.createDateFormat(); final SimpleDateFormat xmlDateTimeFormat = JsonUtils.createDateTimeFormat(); OBContext.setAdminMode(); try { WidgetClass widgetClass = OBDal.getInstance().get(WidgetClass.class, parameters.get("widgetId")); // Check security: continue only if the widget instance is visible for current user/role WidgetInstance wi = OBDal.getInstance().get(WidgetInstance.class, parameters.get("widgetInstanceId")); boolean accessibleWidgetInForm = false; if (wi == null) { accessibleWidgetInForm = isAccessibleWidgetInForm(widgetClass); } if (!accessibleWidgetInForm && (wi == null || wi.getWidgetClass().getId() != widgetClass.getId())) { // weird stuff: widget class doesn't match widget instance's class, most probably URL is // not generated by UI, but user is typing it log.error("User " + OBContext.getOBContext().getUser() + " with role " + OBContext.getOBContext().getRole() + " is trying to access widget '" + widgetClass.getWidgetTitle() + "' but widget istance doesn't match with class"); throw new OBSecurityException(OBMessageUtils.getI18NMessage("OBCQL_NoAccessToWidget", new String[] { widgetClass.getWidgetTitle() })); } if (!accessibleWidgetInForm && (OBContext.getOBContext() != null && ((wi.getVisibleAtUser() != null && !wi.getVisibleAtUser().getId().equals(OBContext.getOBContext().getUser().getId()))) || (wi.getVisibleAtRole() != null && !wi.getVisibleAtRole().getId() .equals(OBContext.getOBContext().getRole().getId())))) { log.error("User " + OBContext.getOBContext().getUser() + " with role " + OBContext.getOBContext().getRole() + " is trying to access widget '" + widgetClass.getWidgetTitle() + "' which is not granted"); throw new OBSecurityException(OBMessageUtils.getI18NMessage("OBCQL_NoAccessToWidget", new String[] { widgetClass.getWidgetTitle() })); } boolean isExport = "true".equals(parameters.get("exportToFile")); boolean showAll = "true".equals(parameters.get("showAll")); String viewMode = parameters.get("viewMode"); List<OBCQL_QueryColumn> columns = QueryListUtils .getColumns(widgetClass.getOBCQLWidgetQueryList().get(0)); // handle complex criteria try { JSONArray criterias = (JSONArray) JsonUtils.buildCriteria(parameters).get("criteria"); for (int i = 0; i < criterias.length(); i++) { final JSONObject criteria = criterias.getJSONObject(i); parameters.put(criteria.getString("fieldName"), criteria.getString("value")); parameters.put(criteria.getString("fieldName") + OPERATOR, criteria.getString("operator")); } } catch (JSONException e) { // Ignore exception. } OBCQL_WidgetQuery widgetQueryInstance = widgetClass.getOBCQLWidgetQueryList().get(0); String HQL = widgetQueryInstance.getHQL(); // Parse the HQL in case that optional filters are required HQL = parseOptionalFilters(HQL, viewMode, parameters, columns, xmlDateFormat); boolean fetchingSummaryFields = parameters.containsKey(JsonConstants.SUMMARY_PARAMETER); if (fetchingSummaryFields) { // if the request comes from the summary row, update the select clause so that it obtains // the values for the summary fields HQL = updateHQLWithSummaryFields(HQL, parameters.get(JsonConstants.SUMMARY_PARAMETER), widgetQueryInstance); } if (parameters.containsKey(JsonConstants.SORTBY_PARAMETER)) { HQL = updateSortByFields(HQL, parameters.get(JsonConstants.SORTBY_PARAMETER)); } Query widgetQuery = null; try { widgetQuery = OBDal.getInstance().getSession().createQuery(HQL); } catch (Exception e) { if (fetchingSummaryFields) { log.error("Exception while fetching the summary columns of the widget " + widgetClass.getWidgetTitle() + ". It is not supported using as summaries columns that are defined using a subquery, or that are defined using a summary function. \n Query = " + HQL); } else { log.error("Exception while executing the HQL query to fetch the data of the widget " + widgetClass.getWidgetTitle() + ". \n Query = " + HQL); } final List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); return result; } String[] queryAliases = widgetQuery.getReturnAliases(); if (!isExport && "widget".equals(viewMode) && !showAll) { int rowsNumber = Integer.valueOf( (parameters.get("rowsNumber") != null && !parameters.get("rowsNumber").equals("null")) ? parameters.get("rowsNumber") : "10"); widgetQuery.setMaxResults(rowsNumber); } else if (!isExport) { if (startRow > 0) { widgetQuery.setFirstResult(startRow); } if (endRow > startRow) { widgetQuery.setMaxResults(endRow - startRow + 1); } } String[] params = widgetQuery.getNamedParameters(); if (params.length > 0) { HashMap<String, Object> parameterValues = getParameterValues(parameters, widgetClass); for (int i = 0; i < params.length; i++) { String namedParam = params[i]; boolean isParamSet = false; if (parameterValues.containsKey(namedParam)) { Object value = parameterValues.get(namedParam); if (value instanceof Collection<?>) { widgetQuery.setParameterList(namedParam, (Collection<?>) value); } else if (value instanceof Object[]) { widgetQuery.setParameterList(namedParam, (Object[]) value); } else if (value instanceof String && isDate(namedParam, widgetClass.getOBUIAPPParameterEMObkmoWidgetClassIDList())) { widgetQuery.setParameter(namedParam, convertToDate((String) value)); } else { widgetQuery.setParameter(namedParam, value); } isParamSet = true; } if (!isParamSet) { // TODO: throw an exception } } } final List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); if (fetchingSummaryFields) { // process the response for the summary row Map<String, Object> summaryData = new LinkedHashMap<String, Object>(); try { JSONObject summaryFieldsObject = new JSONObject( parameters.get(JsonConstants.SUMMARY_PARAMETER)); Iterator<?> summaryFieldNameIterator = summaryFieldsObject.keys(); Object uniqueResult = widgetQuery.uniqueResult(); if (uniqueResult instanceof Object[]) { // handles the case where the values of several summary fields are request Object[] summaryValues = (Object[]) uniqueResult; int i = 0; while (summaryFieldNameIterator.hasNext()) { String summaryFieldName = (String) summaryFieldNameIterator.next(); summaryData.put(summaryFieldName, summaryValues[i++]); } } else { // handles the case where the value of just one summary field is request String summaryFieldName = (String) summaryFieldsObject.names().get(0); summaryData.put(summaryFieldName, uniqueResult); } summaryData.put("isGridSummary", true); } catch (Exception e) { } result.add(summaryData); } else { // process the response for the grid for (Object objResult : widgetQuery.list()) { final Map<String, Object> data = new LinkedHashMap<String, Object>(); Object[] resultList = new Object[1]; if (objResult instanceof Object[]) { resultList = (Object[]) objResult; } else { resultList[0] = objResult; } for (OBCQL_QueryColumn column : columns) { UIDefinition uiDefinition = UIDefinitionController.getInstance() .getUIDefinition(column.getReference()); DomainType domainType = uiDefinition.getDomainType(); // TODO: throw an exception if the display expression doesn't match any returned alias. for (int i = 0; i < queryAliases.length; i++) { if (queryAliases[i].equals(column.getDisplayExpression()) || (!isExport && queryAliases[i].equals(column.getLinkExpression()))) { Object value = resultList[i]; if (domainType instanceof DateDomainType || domainType instanceof DateDomainType) { value = xmlDateFormat.format(value); } else if (value instanceof Timestamp) { value = xmlDateTimeFormat.format(value); value = JsonUtils.convertToCorrectXSDFormat((String) value); } if (domainType instanceof BooleanDomainType) { if (value instanceof String) { value = ((PrimitiveDomainType) domainType).createFromString((String) value); } } if (!isExport) { data.put(queryAliases[i], value); } else { data.put(QueryListUtils.getColumnLabel(column), value); } } } } result.add(data); } } return result; } finally { OBContext.restorePreviousMode(); } } /** * Updates the order by clause of the HQL query so that it obtains the values for the summary * fields. If the HQL query already contains order by fields, the new fields are appended for the * existing fields. * * @param hql * original HQL query * @param sortBy * parameter that contains sortBy field values * @return an updated HQL query that will set the order by fields */ private String updateSortByFields(String hql, String sortBy) { String[] fieldList = null; String sortByClause = "", hqlString = hql; if (sortBy.contains(",")) { fieldList = sortBy.split(","); } if (hqlString.toLowerCase().contains("order by")) { if (fieldList == null) { sortByClause = sortBy.startsWith("-") ? sortBy.substring(1, sortBy.length()) + " desc " : sortBy; } else { // sort by multiple columns for (String field : fieldList) { sortByClause = field.startsWith("-") ? sortByClause.concat(field.substring(1, field.length())) + " desc " : sortByClause.concat(field); } } int sortByIndex = hqlString.toLowerCase().indexOf("order by"); hqlString = hqlString.substring(0, sortByIndex + "order by".length() + 1) + sortByClause + "," + hqlString.substring(sortByIndex + "order by".length() + 1); } else { hqlString = hqlString.concat(" order by " + sortByClause); } return hqlString; } /** * Updates the select clause of the HQL query so that it obtains the values for the summary fields * * @param hQL * original HQL query * @param summaryParametersString * parameter that contains pairs of summaryField - summaryFunction values * @param widgetQuery * the instance of the widget, used to obtain the whereCLauseLeftPart of the summary * parameter * @return an updated HQL query that will obtain the values for the summary fields */ private String updateHQLWithSummaryFields(String hQL, String summaryParametersString, OBCQL_WidgetQuery widgetQuery) { // get rid of the original select clause, a new one is going to be built String updatedHQL = removeSelectClause(hQL); // the order clause is not needed when obtaining the values for the summary fields updatedHQL = removeOrderByClause(updatedHQL); try { JSONObject summaryFieldsObject = new JSONObject(summaryParametersString); Iterator<?> summaryFieldNameIterator = summaryFieldsObject.keys(); StringBuilder selectClause = new StringBuilder("select "); boolean first = true; while (summaryFieldNameIterator.hasNext()) { String summaryFieldName = (String) summaryFieldNameIterator.next(); String whereClauseLeftPart = getWhereClauseLeftPart(widgetQuery, summaryFieldName); // if the column has whereClauseLeftPart, use it to support using columns with aliases // see issue https://issues.openbravo.com/view.php?id=29174 String summaryColumnInnerClause = (whereClauseLeftPart.isEmpty() ? summaryFieldName : whereClauseLeftPart); String summaryFunction = summaryFieldsObject.getString(summaryFieldName); if (!first) { selectClause.append(", "); } else { first = false; } // only three summary functions are available for the columns of Query/List widgets: count, // sum and avg if ("count".equals(summaryFunction)) { selectClause.append("count(*)"); } else if ("sum".equals(summaryFunction)) { selectClause.append("sum(" + summaryColumnInnerClause + ")"); } else if ("avg".equals(summaryFunction)) { selectClause.append("sum(" + summaryColumnInnerClause + ")/count(*)"); } } updatedHQL = selectClause.toString() + " " + updatedHQL; } catch (JSONException e) { log.error("Error obtaining the values of the summary fields", e); } return updatedHQL; } private String getWhereClauseLeftPart(OBCQL_WidgetQuery widgetQuery, String summaryFieldName) { OBCriteria<OBCQL_QueryColumn> columnCriteria = OBDal.getInstance().createCriteria(OBCQL_QueryColumn.class); columnCriteria.add(Restrictions.eq(OBCQL_QueryColumn.PROPERTY_WIDGETQUERY, widgetQuery)); columnCriteria.add(Restrictions.eq(OBCQL_QueryColumn.PROPERTY_DISPLAYEXPRESSION, summaryFieldName)); OBCQL_QueryColumn queryColumn = (OBCQL_QueryColumn) columnCriteria.uniqueResult(); return (queryColumn != null && queryColumn.getWhereClauseLeftPart() != null ? queryColumn.getWhereClauseLeftPart() : ""); } /** * Removes the select clause of a hql query * * @param hql * the original hql query * @return the original hql query without its select clause */ private String removeSelectClause(String hql) { String hqlWithoutSelectClause = hql; if (hqlWithoutSelectClause.toLowerCase().indexOf(" from ") != -1) { hqlWithoutSelectClause = hqlWithoutSelectClause .substring(hqlWithoutSelectClause.toLowerCase().indexOf(" from ")); } else if (hqlWithoutSelectClause.toLowerCase().indexOf("\nfrom ") != -1) { hqlWithoutSelectClause = hqlWithoutSelectClause .substring(hqlWithoutSelectClause.toLowerCase().indexOf("\nfrom ")); } return hqlWithoutSelectClause; } /** * Removes the order by clause of a hql query * * @param hql * the original hql query * @return the original hql query without its select clause */ private String removeOrderByClause(String hql) { String hqlWithoutOrderByClause = hql; if (hqlWithoutOrderByClause.toLowerCase().indexOf(" order by ") != -1) { hqlWithoutOrderByClause = hqlWithoutOrderByClause.substring(0, hqlWithoutOrderByClause.toLowerCase().indexOf(" order by ")); } else if (hqlWithoutOrderByClause.toLowerCase().indexOf("\norder by ") != -1) { hqlWithoutOrderByClause = hqlWithoutOrderByClause.substring(0, hqlWithoutOrderByClause.toLowerCase().indexOf("\norder by ")); } return hqlWithoutOrderByClause; } // Checks if the widget is embedded in a tab accessible by the user private boolean isAccessibleWidgetInForm(WidgetClass widgetClass) { OBCriteria<WidgetReference> widgetInFormCriteria = OBDal.getInstance() .createCriteria(WidgetReference.class); widgetInFormCriteria.add(Restrictions.eq(WidgetReference.PROPERTY_WIDGETCLASS, widgetClass)); List<Window> windowList = new ArrayList<Window>(); List<WidgetReference> widgetInFormList = widgetInFormCriteria.list(); for (WidgetReference widgetInForm : widgetInFormList) { List<Column> columnList = widgetInForm.getReference().getADColumnReferenceSearchKeyList(); for (Column column : columnList) { List<Field> fieldList = column.getADFieldList(); for (Field field : fieldList) { windowList.add(field.getTab().getWindow()); } } } if (windowList.isEmpty()) { // The widget is not embedded in any window return false; } else { OBCriteria<WindowAccess> accessibleWindowCriteria = OBDal.getInstance() .createCriteria(WindowAccess.class); accessibleWindowCriteria .add(Restrictions.eq(WindowAccess.PROPERTY_ROLE, OBContext.getOBContext().getRole())); accessibleWindowCriteria.add(Restrictions.in(WindowAccess.PROPERTY_WINDOW, windowList)); int count = accessibleWindowCriteria.count(); // If the widget is embedded in at least one window accessible by the user, return true return (count > 0); } } // Converts and object from String to Date private Date convertToDate(String value) { DateDomainType domainType = new DateDomainType(); return (Date) domainType.createFromString(value); } // Check if the reference of a parameter is a Date private boolean isDate(String paramName, List<Parameter> parameterList) { Parameter parameterToCheck = null; for (Parameter p : parameterList) { if (p.getDBColumnName().equals(paramName)) { parameterToCheck = p; break; } } if (parameterToCheck == null) { return false; } else { DomainType domainType = ModelProvider.getInstance() .getReference(parameterToCheck.getReference().getId()).getDomainType(); if (domainType.getClass().equals(DateDomainType.class)) { return true; } else { return false; } } } /** * Returns a HashMap with the values of the parameters included on the given widget instance. * * @param parameters * the parameters passed in from the request * @param widgetClass * the widget class to which the parameters belong to * @return a HashMap<String, Object> with the value of each parameter mapped by the DBColumnName * of the parameter. */ private HashMap<String, Object> getParameterValues(Map<String, String> parameters, WidgetClass widgetClass) { HashMap<String, Object> parameterValues = new HashMap<String, Object>(); // get serializedValues from request (if present) String serializedParams = parameters.get("serializedParameters"); if (serializedParams != null) { try { JSONObject json = new JSONObject(serializedParams); for (Parameter parameter : widgetClass.getOBUIAPPParameterEMObkmoWidgetClassIDList()) { if (parameter.isFixed()) { parameterValues.put(parameter.getDBColumnName(), ParameterUtils.getParameterFixedValue(parameters, parameter)); } else { if (json.has(parameter.getDBColumnName())) { parameterValues.put(parameter.getDBColumnName(), json.get(parameter.getDBColumnName())); } else { // TODO: not fixed & value missing -> error (prepared to be handled in caller, but not // yet implemented) } } } } catch (JSONException e) { log.error("Error processing client parameters", e); } } else { // data send without serializedParams (should not happen) throw new OBException("Missing serializedParameters value in request"); } return parameterValues; } private String parseOptionalFilters(String _HQL, String viewMode, Map<String, String> parameters, List<OBCQL_QueryColumn> columns, SimpleDateFormat xmlDateFormat) { StringBuffer optionalFilter = new StringBuffer(" 1=1 "); String HQL = _HQL; // Parse for columns filtered by grid's filter row on maximized view. If we are not on maximized // view return the HQL without parsing. if ("maximized".equals(viewMode)) { for (OBCQL_QueryColumn column : columns) { if (column.isCanBeFiltered()) { String value = parameters.get(column.getDisplayExpression()); String operator = parameters.get(column.getDisplayExpression() + OPERATOR); if (column.getReference().getName().equals("YesNo") && value != null) { if (value.equals("true")) { value = "Y"; } else { value = "N"; } } String whereClause = " 1=1 "; if (value != null) { whereClause = getWhereClause(value, column, xmlDateFormat, operator); } if (HQL.contains("@" + column.getDisplayExpression() + "@")) { HQL = HQL.replace("@" + column.getDisplayExpression() + "@", whereClause); } else { optionalFilter.append(" and " + whereClause); } } } } HQL = HQL.replace(OPTIONAL_FILTERS, optionalFilter.toString()); return HQL; } private String getWhereClause(String value, OBCQL_QueryColumn column, SimpleDateFormat xmlDateFormat, String operator) { String whereClause = ""; DomainType domainType = ModelProvider.getInstance().getReference(column.getReference().getId()) .getDomainType(); if (domainType.getClass().getSuperclass().equals(BigDecimalDomainType.class) || domainType.getClass().equals(LongDomainType.class)) { if (StringUtils.isNotEmpty(value)) { whereClause = column.getWhereClauseLeftPart() + " " + AdvancedQueryBuilder.getHqlOperator(operator) + " " + value; } else { whereClause = " 1=1 "; } } else if (domainType.getClass().equals(DateDomainType.class)) { try { final Calendar cal = Calendar.getInstance(); cal.setTime(xmlDateFormat.parse(value)); whereClause = " (day(" + column.getWhereClauseLeftPart() + ") = " + cal.get(Calendar.DATE); whereClause += "\n and month(" + column.getWhereClauseLeftPart() + ") = " + (cal.get(Calendar.MONTH) + 1); whereClause += "\n and year(" + column.getWhereClauseLeftPart() + ") = " + cal.get(Calendar.YEAR) + ") "; } catch (Exception e) { // ignore these errors, just don't filter then // add a dummy whereclause to make the query format correct whereClause = " 1=1 "; } } else { whereClause = "upper(" + column.getWhereClauseLeftPart() + ")"; whereClause += " LIKE "; whereClause += "'%" + value.toUpperCase().replaceAll(" ", "%") + "%'"; } return whereClause; } public List<DataSourceProperty> getDataSourceProperties(Map<String, Object> parameters) { // note datasource properties are not cached as the component is // re-used within one request thread final List<DataSourceProperty> dsProperties = new ArrayList<DataSourceProperty>(); OBContext.setAdminMode(); try { WidgetClass widgetClass = (WidgetClass) parameters.get(QueryListWidgetProvider.WIDGETCLASS_PARAMETER); if (!widgetClass.getOBCQLWidgetQueryList().isEmpty()) { for (OBCQL_QueryColumn column : QueryListUtils .getColumns(widgetClass.getOBCQLWidgetQueryList().get(0))) { Reference reference = column.getReference(); if (column.getReferenceSearchKey() != null) { reference = column.getReferenceSearchKey(); } final DataSourceProperty dsProperty = new DataSourceProperty(); dsProperty.setName(column.getDisplayExpression()); dsProperty.setId(false); dsProperty.setMandatory(false); dsProperty.setAuditInfo(false); dsProperty.setUpdatable(false); final UIDefinition uiDefinition = UIDefinitionController.getInstance() .getUIDefinition(reference); dsProperty.setBoolean(uiDefinition instanceof YesNoUIDefinition); dsProperty.setPrimitive(!(uiDefinition instanceof ForeignKeyUIDefinition)); dsProperty.setUIDefinition(uiDefinition); if (dsProperty.isPrimitive()) { dsProperty.setPrimitiveObjectType( ((PrimitiveDomainType) uiDefinition.getDomainType()).getPrimitiveType()); dsProperty.setNumericType(uiDefinition instanceof NumberUIDefinition); if (uiDefinition instanceof EnumUIDefinition) { if (column.getReferenceSearchKey() == null) { log.warn("In widget " + column.getWidgetQuery().getWidgetClass().getWidgetTitle() + " column " + column.getDisplayExpression() + " is of enum type but does not define sub reference."); } else { Set<String> allowedValues = DataSourceProperty .getAllowedValues(column.getReferenceSearchKey()); dsProperty.setAllowedValues(allowedValues); dsProperty.setValueMap(DataSourceProperty.createValueMap(allowedValues, column.getReferenceSearchKey().getId())); } } } else { } dsProperties.add(dsProperty); } } return dsProperties; } finally { OBContext.restorePreviousMode(); } } protected void sort(String sortBy, List<Map<String, Object>> data) { Collections.sort(data, new DataComparator(sortBy)); } // can only be used if the comparedBy is a string private static class DataComparator implements Comparator<Map<String, Object>> { private ArrayList<String> compareByArray; public DataComparator(String compareBy) { this.compareByArray = new ArrayList<String>(); if (compareBy.contains(JsonConstants.IN_PARAMETER_SEPARATOR)) { final String[] separatedValues = compareBy.split(JsonConstants.IN_PARAMETER_SEPARATOR); for (String separatedValue : separatedValues) { this.compareByArray.add(separatedValue); } } else { this.compareByArray.add(compareBy); } } @Override public int compare(Map<String, Object> o1, Map<String, Object> o2) { for (String compareBy : compareByArray) { int ascending = 1; if (compareBy.startsWith("-")) { ascending = -1; compareBy = compareBy.substring(1); } final Object v1 = o1.get(compareBy); final Object v2 = o2.get(compareBy); if (v1 == null) { return -1 * ascending; } else if (v2 == null) { return 1 * ascending; } int returnValue = 0; if (v1 instanceof Date && v2 instanceof Date) { returnValue = ((Date) v1).compareTo((Date) v2) * ascending; } else if (v1 instanceof Timestamp && v2 instanceof Timestamp) { returnValue = ((Timestamp) v1).compareTo((Timestamp) v2) * ascending; } else if (v1 instanceof Long && v2 instanceof Long) { returnValue = ((Long) v1).compareTo((Long) v2) * ascending; } else if (v1 instanceof BigDecimal && v2 instanceof BigDecimal) { returnValue = ((BigDecimal) v1).compareTo((BigDecimal) v2) * ascending; } else if (v1 instanceof String && v2 instanceof String) { returnValue = ((String) v1).compareTo((String) v2) * ascending; } else { log.warn("Comparing on property " + compareBy + " for objects " + v1 + "/" + v2 + ". " + "But value is are of different classes or an instance of a not supported class. " + "Returning default compare value."); returnValue = 0; } if (returnValue != 0) { return returnValue; } } return 0; } } }