001    /*
002     * Copyright (c) 1998-2014 ChemAxon Ltd. All Rights Reserved.
003     *
004     * This software is the confidential and proprietary information of
005     * ChemAxon. You shall not disclose such Confidential Information
006     * and shall use it only in accordance with the terms of the agreements
007     * you entered into with ChemAxon.
008     *
009     */
010    package com.chemaxon.overlap.storage;
011    
012    import com.chemaxon.overlap.io.StandardizerWrapper;
013    import chemaxon.struc.Molecule;
014    import com.chemaxon.descriptors.common.Descriptor;
015    import com.chemaxon.descriptors.common.DescriptorGenerator;
016    import java.util.List;
017    import java.util.concurrent.Callable;
018    import org.apache.commons.logging.Log;
019    import org.apache.commons.logging.LogFactory;
020    
021    /**
022     * Process a set of PQE elements.
023     *
024     * <p>This implementation should not fail; failures are reported individually.</p>
025     *
026     * @param <D>   Represented descriptor
027     */
028    class Process<D extends Descriptor> implements Callable<List<ProcessQueueItem<D>>> {
029        /**
030         * Logger to use.
031         */
032        private final Log log = LogFactory.getLog(Process.class);
033    
034        /**
035         * Tasks to process.
036         */
037        private final List<ProcessQueueItem<D>> itemsToProcess;
038    
039    
040        /**
041         * Underlying descriptor generator.
042         */
043        private final DescriptorGenerator<D> generator;
044    
045        /**
046         * Standardizer to use.
047         */
048        private final StandardizerWrapper standardizer;
049    
050        /**
051         * Construct.
052         *
053         * @param generator         Descriptor generator to use
054         * @param standardizer      Standardizer to invoke on molecules
055         * @param itemsToProcess    Tasks to process sequentially. This reference will returned upon completion.
056         */
057        Process(DescriptorGenerator<D> generator, StandardizerWrapper standardizer,
058                List<ProcessQueueItem<D>> itemsToProcess) {
059            this.itemsToProcess = itemsToProcess;
060            this.standardizer = standardizer;
061            this.generator = generator;
062        }
063    
064        /**
065         * Process an individual item.
066         *
067         * <p>This methods should not throw exceptions. However it is recommended to consider possible exceptions as
068         * processing error.</p>
069         *
070         * TODO: revise the above policy recommendation
071         *
072         * @param item  Item to process
073         */
074        private void processItem(ProcessQueueItem<D> item) {
075            if (this.log.isTraceEnabled()) {
076                this.log.trace("Process readno " + item.getReadno());
077            }
078            // Invoke parse; if failed return
079            // Note that this method call wont throw exception
080            if (!item.parse()) {
081                if (this.log.isTraceEnabled()) {
082                    this.log.trace("    Parse error " + item.getError().getMessage(), item.getError());
083                }
084                return;
085            }
086    
087            // This method should not throw exception
088            final Molecule m = item.getMol();
089    
090            // Standardize if required
091            // be prepared for error(s)
092            try {
093                this.standardizer.standardize(m);
094            } catch (Exception e) {
095                item.processError(e);
096                if (this.log.isTraceEnabled()) {
097                    this.log.trace("    Standardization error " + e.getMessage(), e);
098                }
099                return;
100            }
101    
102            // Generate descriptor's bare form
103            final D d;
104            try {
105                d = this.generator.getBareDescriptor(this.generator.generateDescriptor(m));
106                item.ok(d);
107            } catch (Exception e) {
108                item.processError(e);
109                if (this.log.isTraceEnabled()) {
110                    this.log.trace("     Descriptor generation error " + e.getMessage(), e);
111                }
112            }
113    
114        }
115    
116        @Override
117        public List<ProcessQueueItem<D>> call() throws Exception {
118            if (this.log.isDebugEnabled()) {
119                this.log.debug("run()");
120            }
121            // Run through items sequentially
122            for (ProcessQueueItem<D> item : this.itemsToProcess) {
123                // TODO: is it ok?
124                if (Thread.interrupted()) {
125                    throw new InterruptedException();
126                }
127                try {
128                    processItem(item);
129                } catch (Exception e) {
130                    // This should not happen; indicates programmer error
131                    // Register as processing error; continue and log
132                    // TODO: Revise this decision; maybe error propagation should be desirable
133                    item.processError(e);
134                    if (this.log.isErrorEnabled()) {
135                        this.log.error("Unexpected exception at " + item.toString() + ": " + e.getMessage()
136                                + ". Registered as failed molecule processing.", e);
137                    }
138                }
139            }
140            if (this.log.isDebugEnabled()) {
141                this.log.debug("all done.");
142            }
143            return this.itemsToProcess;
144        }
145    
146    }