private static Object getReferencedId(DataRecord next, ReferenceFieldMetadata field) { DataRecord record = (DataRecord) next.get(field); if (record != null) { Collection<FieldMetadata> keyFields = record.getType().getKeyFields(); if (keyFields.size() == 1) { return record.get(keyFields.iterator().next()); } else { List<Object> compositeKeyValues = new ArrayList<Object>(keyFields.size()); for (FieldMetadata keyField : keyFields) { compositeKeyValues.add(record.get(keyField)); } return compositeKeyValues; } } else { return StringUtils.EMPTY; } }
@Override public StorageResults visit(Select select) { // TMDM-4654: Checks if entity has a composite PK. Set<ComplexTypeMetadata> compositeKeyTypes = new HashSet<ComplexTypeMetadata>(); // TMDM-7496: Search should include references to reused types Collection<ComplexTypeMetadata> types = new HashSet<ComplexTypeMetadata>(select.accept(new SearchTransitiveClosure())); for (ComplexTypeMetadata type : types) { if (type.getKeyFields().size() > 1) { compositeKeyTypes.add(type); } } if (!compositeKeyTypes.isEmpty()) { StringBuilder message = new StringBuilder(); Iterator it = compositeKeyTypes.iterator(); while (it.hasNext()) { ComplexTypeMetadata compositeKeyType = (ComplexTypeMetadata) it.next(); message.append(compositeKeyType.getName()); if (it.hasNext()) { message.append(','); } } throw new FullTextQueryCompositeKeyException(message.toString()); } // Removes Joins and joined fields. List<Join> joins = select.getJoins(); if (!joins.isEmpty()) { Set<ComplexTypeMetadata> joinedTypes = new HashSet<ComplexTypeMetadata>(); for (Join join : joins) { joinedTypes.add(join.getRightField().getFieldMetadata().getContainingType()); } for (ComplexTypeMetadata joinedType : joinedTypes) { types.remove(joinedType); } List<TypedExpression> filteredFields = new LinkedList<TypedExpression>(); for (TypedExpression expression : select.getSelectedFields()) { if (expression instanceof Field) { FieldMetadata fieldMetadata = ((Field) expression).getFieldMetadata(); if (joinedTypes.contains(fieldMetadata.getContainingType())) { TypeMapping mapping = mappings.getMappingFromDatabase(fieldMetadata.getContainingType()); filteredFields.add( new Alias( new StringConstant(StringUtils.EMPTY), mapping.getUser(fieldMetadata).getName())); } else { filteredFields.add(expression); } } else { filteredFields.add(expression); } } selectedFields.clear(); selectedFields.addAll(filteredFields); } // Handle condition Condition condition = select.getCondition(); if (condition == null) { throw new IllegalArgumentException("Expected a condition in select clause but got 0."); } // Create Lucene query (concatenates all sub queries together). FullTextSession fullTextSession = Search.getFullTextSession(session); Query parsedQuery = select.getCondition().accept(new LuceneQueryGenerator(types)); // Create Hibernate Search query Set<Class> classes = new HashSet<Class>(); for (ComplexTypeMetadata type : types) { String className = ClassCreator.getClassName(type.getName()); try { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); classes.add(contextClassLoader.loadClass(className)); } catch (ClassNotFoundException e) { throw new RuntimeException("Could not find class '" + className + "'.", e); } } FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( parsedQuery, classes.toArray(new Class<?>[classes.size()])); // Very important to leave this null (would disable ability to search across different types) fullTextQuery.setCriteriaQuery(null); fullTextQuery.setSort(Sort.RELEVANCE); // Default sort (if no order by specified). query = EntityFinder.wrap( fullTextQuery, (HibernateStorage) storage, session); // ensures only MDM entity objects are returned. // Order by for (OrderBy current : select.getOrderBy()) { current.accept(this); } // Paging Paging paging = select.getPaging(); paging.accept(this); pageSize = paging.getLimit(); boolean hasPaging = pageSize < Integer.MAX_VALUE; if (!hasPaging) { return createResults(query.scroll(ScrollMode.FORWARD_ONLY)); } else { return createResults(query.list()); } }
private StorageResults createResults(final List list) { CloseableIterator<DataRecord> iterator; if (selectedFields.isEmpty()) { iterator = new ListIterator(mappings, storageClassLoader, list.iterator(), callbacks); } else { iterator = new ListIterator(mappings, storageClassLoader, list.iterator(), callbacks) { @Override public DataRecord next() { final DataRecord next = super.next(); final ComplexTypeMetadata explicitProjectionType = new ComplexTypeMetadataImpl(StringUtils.EMPTY, Storage.PROJECTION_TYPE, false); final DataRecord nextRecord = new DataRecord(explicitProjectionType, UnsupportedDataRecordMetadata.INSTANCE); VisitorAdapter<Void> visitor = new VisitorAdapter<Void>() { private String aliasName; @Override public Void visit(Field field) { FieldMetadata fieldMetadata = field.getFieldMetadata(); TypeMapping mapping = mappings.getMappingFromDatabase(fieldMetadata.getContainingType()); if (mapping != null && mapping.getUser(fieldMetadata) != null) { fieldMetadata = mapping.getUser(fieldMetadata); } Object value; if (fieldMetadata instanceof ReferenceFieldMetadata) { value = getReferencedId(next, (ReferenceFieldMetadata) fieldMetadata); } else { value = next.get(fieldMetadata); } if (aliasName != null) { SimpleTypeMetadata fieldType = new SimpleTypeMetadata( XMLConstants.W3C_XML_SCHEMA_NS_URI, fieldMetadata.getType().getName()); fieldMetadata = new SimpleTypeFieldMetadata( explicitProjectionType, false, false, false, aliasName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(), StringUtils.EMPTY); explicitProjectionType.addField(fieldMetadata); } else { explicitProjectionType.addField(fieldMetadata); } nextRecord.set(fieldMetadata, value); return null; } @Override public Void visit(StringConstant constant) { if (aliasName != null) { SimpleTypeMetadata fieldType = new SimpleTypeMetadata( XMLConstants.W3C_XML_SCHEMA_NS_URI, Types.STRING); FieldMetadata fieldMetadata = new SimpleTypeFieldMetadata( explicitProjectionType, false, false, false, aliasName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(), StringUtils.EMPTY); explicitProjectionType.addField(fieldMetadata); nextRecord.set(fieldMetadata, constant.getValue()); } else { throw new IllegalStateException( "Expected an alias for a constant expression."); } return null; } @Override public Void visit(Count count) { if (aliasName != null) { SimpleTypeMetadata fieldType = new SimpleTypeMetadata( XMLConstants.W3C_XML_SCHEMA_NS_URI, count.getTypeName()); FieldMetadata fieldMetadata = new SimpleTypeFieldMetadata( explicitProjectionType, false, false, false, aliasName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(), StringUtils.EMPTY); explicitProjectionType.addField(fieldMetadata); nextRecord.set(fieldMetadata, list.size()); } return null; } @Override public Void visit(Alias alias) { aliasName = alias.getAliasName(); { alias.getTypedExpression().accept(this); } aliasName = null; return null; } private Void handleMetadataField(MetadataField field) { SimpleTypeMetadata fieldType = new SimpleTypeMetadata( XMLConstants.W3C_XML_SCHEMA_NS_URI, field.getTypeName()); String fieldName = aliasName == null ? field.getFieldName() : aliasName; SimpleTypeFieldMetadata aliasField = new SimpleTypeFieldMetadata( explicitProjectionType, false, false, false, fieldName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(), StringUtils.EMPTY); explicitProjectionType.addField(aliasField); nextRecord.set(aliasField, field.getReader().readValue(next)); return null; } @Override public Void visit(Timestamp timestamp) { return handleMetadataField(timestamp); } @Override public Void visit(TaskId taskId) { return handleMetadataField(taskId); } @Override public Void visit(StagingStatus stagingStatus) { return handleMetadataField(stagingStatus); } @Override public Void visit(StagingError stagingError) { return handleMetadataField(stagingError); } @Override public Void visit(StagingSource stagingSource) { return handleMetadataField(stagingSource); } @Override public Void visit(StagingBlockKey stagingBlockKey) { return handleMetadataField(stagingBlockKey); } @Override public Void visit(Type type) { FieldMetadata fieldMetadata = type.getField().getFieldMetadata(); SimpleTypeMetadata fieldType = new SimpleTypeMetadata(XMLConstants.W3C_XML_SCHEMA_NS_URI, Types.STRING); SimpleTypeFieldMetadata aliasField = new SimpleTypeFieldMetadata( explicitProjectionType, false, false, false, aliasName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(), StringUtils.EMPTY); explicitProjectionType.addField(aliasField); DataRecord dataRecord = (DataRecord) next.get(fieldMetadata.getName()); if (dataRecord != null) { nextRecord.set(aliasField, dataRecord.getType().getName()); } else { nextRecord.set(aliasField, StringUtils.EMPTY); } return null; } }; for (TypedExpression selectedField : selectedFields) { selectedField.accept(visitor); } return nextRecord; } }; } return new FullTextStorageResults(pageSize, query.getResultSize(), iterator); }