com.amalto.core.storage.hibernate.ProjectionIterator.java Source code

Java tutorial

Introduction

Here is the source code for com.amalto.core.storage.hibernate.ProjectionIterator.java

Source

/*
 * Copyright (C) 2006-2016 Talend Inc. - www.talend.com
 * 
 * This source code is available under agreement available at
 * %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
 * 
 * You should have received a copy of the agreement along with this program; if not, write to Talend SA 9 rue Pages
 * 92150 Suresnes, France
 */

package com.amalto.core.storage.hibernate;

import java.io.IOException;
import java.io.Reader;
import java.sql.Clob;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.xml.XMLConstants;

import com.amalto.core.storage.CloseableIterator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.ScrollableResults;
import org.talend.mdm.commmon.metadata.AliasedFieldMetadata;
import org.talend.mdm.commmon.metadata.ComplexTypeMetadata;
import org.talend.mdm.commmon.metadata.ComplexTypeMetadataImpl;
import org.talend.mdm.commmon.metadata.CompoundFieldMetadata;
import org.talend.mdm.commmon.metadata.FieldMetadata;
import org.talend.mdm.commmon.metadata.MetadataUtils;
import org.talend.mdm.commmon.metadata.ReferenceFieldMetadata;
import org.talend.mdm.commmon.metadata.SimpleTypeFieldMetadata;
import org.talend.mdm.commmon.metadata.SimpleTypeMetadata;
import org.talend.mdm.commmon.metadata.TypeMetadata;
import org.talend.mdm.commmon.metadata.Types;

import com.amalto.core.query.user.Alias;
import com.amalto.core.query.user.Count;
import com.amalto.core.query.user.Distinct;
import com.amalto.core.query.user.Field;
import com.amalto.core.query.user.Max;
import com.amalto.core.query.user.Min;
import com.amalto.core.query.user.StringConstant;
import com.amalto.core.query.user.Type;
import com.amalto.core.query.user.TypedExpression;
import com.amalto.core.query.user.VisitorAdapter;
import com.amalto.core.query.user.metadata.GroupSize;
import com.amalto.core.query.user.metadata.StagingBlockKey;
import com.amalto.core.query.user.metadata.StagingError;
import com.amalto.core.query.user.metadata.StagingSource;
import com.amalto.core.query.user.metadata.StagingStatus;
import com.amalto.core.query.user.metadata.TaskId;
import com.amalto.core.query.user.metadata.Timestamp;
import com.amalto.core.storage.Storage;
import com.amalto.core.storage.record.DataRecord;
import com.amalto.core.storage.record.metadata.UnsupportedDataRecordMetadata;

class ProjectionIterator implements CloseableIterator<DataRecord> {

    private static final Logger LOGGER = Logger.getLogger(ProjectionIterator.class);

    private final CloseableIterator<Object> iterator;

    private final List<TypedExpression> selectedFields;

    private final Set<ResultsCallback> callbacks;

    private final MappingRepository mappingMetadataRepository;

    private boolean firstNextCall = true;

    private boolean isClosed;

    public ProjectionIterator(MappingRepository mappingMetadataRepository, CloseableIterator<Object> iterator,
            List<TypedExpression> selectedFields, Set<ResultsCallback> callbacks) {
        this.iterator = iterator;
        this.selectedFields = selectedFields;
        this.callbacks = callbacks;
        this.mappingMetadataRepository = mappingMetadataRepository;
    }

    public ProjectionIterator(MappingRepository mappingMetadataRepository, final ScrollableResults results,
            List<TypedExpression> selectedFields, final Set<ResultsCallback> callbacks) {
        this(mappingMetadataRepository, new CloseableIterator<Object>() {

            private boolean hasNext;

            private boolean isClosed = false;

            private boolean consumedResult = true;

            @Override
            public boolean hasNext() {
                if (!consumedResult) {
                    return hasNext;
                }
                try {
                    hasNext = results.next();
                    consumedResult = false;
                    return hasNext;
                } catch (Exception e) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Unable to check for next result.", e); //$NON-NLS-1$
                    }
                    return false;
                }
            }

            @Override
            public Object next() {
                consumedResult = true;
                return results.get();
            }

            @Override
            public void remove() {
            }

            @Override
            public void close() throws IOException {
                if (!isClosed) {
                    try {
                        results.close();
                    } finally {
                        isClosed = true;
                    }
                }
            }
        }, selectedFields, callbacks);
    }

    @Override
    public boolean hasNext() {
        boolean hasNext = iterator.hasNext();
        if (!hasNext) {
            notifyCallbacks();
        }
        return hasNext;
    }

    private void notifyCallbacks() {
        if (!isClosed) {
            // TMDM-6712: Ensure all iterator resources are released.
            try {
                iterator.close();
            } catch (Throwable t) {
                LOGGER.error(t);
            }
            for (ResultsCallback callback : callbacks) {
                try {
                    callback.onEndOfResults();
                } catch (Throwable t) {
                    LOGGER.error(t);
                }
            }
            isClosed = true;
        }
    }

    @Override
    public DataRecord next() {
        if (firstNextCall) {
            for (ResultsCallback callback : callbacks) {
                callback.onBeginOfResults();
            }
            firstNextCall = false;
        }
        DataRecord record;
        try {
            final ComplexTypeMetadata explicitProjectionType = new ComplexTypeMetadataImpl(StringUtils.EMPTY,
                    Storage.PROJECTION_TYPE, false);
            record = new DataRecord(explicitProjectionType, UnsupportedDataRecordMetadata.INSTANCE);
            Object[] values;
            Object next = iterator.next();
            if (next instanceof Object[]) {
                values = (Object[]) next;
            } else {
                values = new Object[] { next };
            }
            ProjectionElementCreator projectionElementCreator = new ProjectionElementCreator(explicitProjectionType,
                    values);
            List<ProjectionElement> elements = new LinkedList<ProjectionElement>();
            for (TypedExpression selectedField : selectedFields) {
                elements.add(selectedField.accept(projectionElementCreator));
            }
            for (ProjectionElement element : elements) {
                explicitProjectionType.addField(element.field);
                record.set(element.field, element.value);
            }
            explicitProjectionType.freeze();
        } catch (Exception e) {
            notifyCallbacks();
            throw new RuntimeException(e);
        }
        return record;
    }

    @Override
    public void remove() {
    }

    @Override
    public void close() throws IOException {
        notifyCallbacks();
    }

    private static class ProjectionElement {

        FieldMetadata field;

        Object value;
    }

    private class ProjectionElementCreator extends VisitorAdapter<ProjectionElement> {

        private final ComplexTypeMetadata explicitProjectionType;

        private final Object[] values;

        int currentIndex = 0;

        boolean isAlias;

        private ProjectionElement currentElement;

        public ProjectionElementCreator(ComplexTypeMetadata explicitProjectionType, Object[] values) {
            this.explicitProjectionType = explicitProjectionType;
            this.values = values;
            isAlias = false;
        }

        private void createElement(String typeName, String fieldName) {
            SimpleTypeMetadata fieldType = new SimpleTypeMetadata(XMLConstants.W3C_XML_SCHEMA_NS_URI, typeName);
            FieldMetadata field = new SimpleTypeFieldMetadata(explicitProjectionType, false, false, false,
                    fieldName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(),
                    Collections.<String>emptyList(), StringUtils.EMPTY);
            currentElement = new ProjectionElement();
            currentElement.field = field;
        }

        private void createElement(String typeName, String fieldName, SimpleTypeFieldMetadata fieldMetadata) {
            SimpleTypeMetadata fieldType = new SimpleTypeMetadata(XMLConstants.W3C_XML_SCHEMA_NS_URI, typeName);
            FieldMetadata field = new SimpleTypeFieldMetadata(fieldMetadata.getContainingType(), false, false,
                    false, fieldName, fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(),
                    Collections.<String>emptyList(), StringUtils.EMPTY);
            currentElement = new ProjectionElement();
            currentElement.field = field;
        }

        private void createElement(String typeName, String aliasName, FieldMetadata aliasedField) {
            SimpleTypeMetadata fieldType = new SimpleTypeMetadata(XMLConstants.W3C_XML_SCHEMA_NS_URI, typeName);
            FieldMetadata field = new AliasedFieldMetadata(explicitProjectionType, false, false, false, aliasName,
                    fieldType, Collections.<String>emptyList(), Collections.<String>emptyList(), aliasedField);
            currentElement = new ProjectionElement();
            currentElement.field = field;
        }

        private void createReferenceElement(ReferenceFieldMetadata fieldMetadata) {
            FieldMetadata field = new ReferenceFieldMetadata(fieldMetadata.getContainingType(), false, false, false,
                    fieldMetadata.getName(), fieldMetadata.getReferencedType(), fieldMetadata.getReferencedField(),
                    fieldMetadata.getForeignKeyInfoFields(), fieldMetadata.getForeignKeyInfoFormat(), false, false,
                    new SimpleTypeMetadata(XMLConstants.W3C_XML_SCHEMA_NS_URI, Types.STRING),
                    Collections.<String>emptyList(), Collections.<String>emptyList(),
                    Collections.<String>emptyList(), StringUtils.EMPTY, StringUtils.EMPTY);
            currentElement = new ProjectionElement();
            currentElement.field = field;
        }

        @Override
        public ProjectionElement visit(Count count) {
            // Do nothing on field creation, count is expected to be nested in a com.amalto.core.query.user.Alias.
            currentElement.value = values[currentIndex++];
            return null;
        }

        @Override
        public ProjectionElement visit(Max max) {
            // Do nothing on field creation, max is expected to be nested in a com.amalto.core.query.user.Alias.
            currentElement.value = values[currentIndex++];
            return null;
        }

        @Override
        public ProjectionElement visit(Min min) {
            // Do nothing on field creation, min is expected to be nested in a com.amalto.core.query.user.Alias.
            currentElement.value = values[currentIndex++];
            return null;
        }

        @Override
        public ProjectionElement visit(Alias alias) {
            isAlias = true;
            if (alias.getTypedExpression() instanceof Field) {
                Field fieldExpression = (Field) alias.getTypedExpression();
                createElement(alias.getTypeName(), alias.getAliasName(), fieldExpression.getFieldMetadata());
            } else {
                createElement(alias.getTypeName(), alias.getAliasName());
            }
            alias.getTypedExpression().accept(this);
            isAlias = false;
            return currentElement;
        }

        @Override
        public ProjectionElement visit(Distinct distinct) {
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(Type type) {
            Object value = values[currentIndex++];
            if (value != null) {
                String typeName = value.toString();
                ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
                if (!(contextClassLoader instanceof StorageClassLoader)) {
                    throw new IllegalStateException("Expected a instance of " + StorageClassLoader.class.getName() //$NON-NLS-1$
                            + " as current class loader."); //$NON-NLS-1$
                }
                try {
                    Class<?> aClass = contextClassLoader.loadClass(ClassCreator.getClassName(typeName));
                    ComplexTypeMetadata typeFromClass = ((StorageClassLoader) contextClassLoader)
                            .getTypeFromClass(aClass);
                    value = mappingMetadataRepository.getMappingFromDatabase(typeFromClass).getUser().getName();
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException("Exception occurred during type name conversion.", e); //$NON-NLS-1$
                }
            }
            currentElement.value = value;
            return currentElement;
        }

        @Override
        public ProjectionElement visit(StringConstant constant) {
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(Timestamp timestamp) {
            if (!isAlias) {
                createElement(timestamp.getTypeName(), "metadata:" + Timestamp.TIMESTAMP_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(TaskId taskId) {
            if (!isAlias) {
                createElement(taskId.getTypeName(), "metadata:" + TaskId.TASK_ID_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(GroupSize groupSize) {
            if (!isAlias) {
                createElement(groupSize.getTypeName(), "metadata:" + GroupSize.GROUP_SIZE_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(Field field) {
            FieldMetadata fieldMetadata = field.getFieldMetadata();
            if (!isAlias) {
                if (fieldMetadata instanceof ReferenceFieldMetadata) {
                    createReferenceElement(((ReferenceFieldMetadata) fieldMetadata));
                } else {
                    TypeMetadata type = fieldMetadata.getType();
                    if (fieldMetadata instanceof SimpleTypeFieldMetadata) {
                        type = MetadataUtils.getSuperConcreteType(type);
                        createElement(type.getName(), fieldMetadata.getName(),
                                (SimpleTypeFieldMetadata) fieldMetadata);
                    } else {
                        createElement(type.getName(), fieldMetadata.getName());
                    }

                }
            }
            if (fieldMetadata instanceof ReferenceFieldMetadata && ((ReferenceFieldMetadata) fieldMetadata)
                    .getReferencedField() instanceof CompoundFieldMetadata) {
                FieldMetadata referencedField = ((ReferenceFieldMetadata) fieldMetadata).getReferencedField();
                int length = ((CompoundFieldMetadata) referencedField).getFields().length;
                Object[] fieldValues = new Object[length];
                System.arraycopy(values, currentIndex, fieldValues, 0, length);
                // Only include composite FK value if there's an actual key value.
                currentElement.value = isNullValue(fieldValues) ? null : fieldValues;
                currentIndex += length;
            } else if (fieldMetadata.getType().getData(TypeMapping.SQL_TYPE) != null
                    && TypeMapping.SQL_TYPE_CLOB.equals(fieldMetadata.getType().getData(TypeMapping.SQL_TYPE))) {
                try {
                    Object clobValue = values[currentIndex++];
                    if (clobValue != null) {
                        Reader characterStream = ((Clob) clobValue).getCharacterStream();
                        currentElement.value = new String(IOUtils.toCharArray(characterStream));
                    }
                } catch (Exception e) {
                    currentElement.value = ""; //$NON-NLS-1$
                    throw new RuntimeException("Unexpected read from clob exception", e); //$NON-NLS-1$
                }
            } else {
                currentElement.value = values[currentIndex++];
            }
            return currentElement;
        }

        private boolean isNullValue(Object[] fieldValues) {
            if (fieldValues == null) {
                return true;
            }
            for (Object o : fieldValues) {
                if (o != null) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public ProjectionElement visit(StagingStatus stagingStatus) {
            if (!isAlias) {
                createElement(stagingStatus.getTypeName(), "metadata:" + StagingStatus.STAGING_STATUS_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(StagingError stagingError) {
            if (!isAlias) {
                createElement(stagingError.getTypeName(), "metadata:" + StagingError.STAGING_ERROR_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(StagingSource stagingSource) {
            if (!isAlias) {
                createElement(stagingSource.getTypeName(), "metadata:" + StagingSource.STAGING_SOURCE_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }

        @Override
        public ProjectionElement visit(StagingBlockKey stagingBlockKey) {
            if (!isAlias) {
                createElement(stagingBlockKey.getTypeName(), "metadata:" + StagingBlockKey.STAGING_BLOCK_ALIAS); //$NON-NLS-1$
            }
            currentElement.value = values[currentIndex++];
            return currentElement;
        }
    }
}