/* * Constellation - An open source and standard compliant SDI * http://www.constellation-sdi.org * * Copyright 2014 Geomatys. * * Licensed 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 org.constellation.sos.io.lucene; import org.apache.lucene.analysis.core.WhitespaceAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldType; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.SimpleFSDirectory; import org.apache.lucene.util.Version; import org.apache.sis.storage.DataStoreException; import org.constellation.generic.database.Automatic; import org.constellation.sos.ws.SOSUtils; import org.geotoolkit.gml.xml.AbstractGML; import org.geotoolkit.lucene.IndexingException; import org.geotoolkit.lucene.index.AbstractIndexer; import org.geotoolkit.observation.xml.Process; import org.geotoolkit.observation.xml.v100.MeasurementType; import org.geotoolkit.sos.xml.SOSMarshallerPool; import org.geotoolkit.swe.xml.Phenomenon; import org.opengis.observation.Observation; import org.opengis.temporal.Instant; import org.opengis.temporal.Period; import org.opengis.temporal.TemporalObject; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.logging.Level; /** * * @author Guilhem Legal (Geomatys) */ public class LuceneObservationIndexer extends AbstractIndexer<Observation> { private File observationDirectory; private File observationTemplateDirectory; private boolean template = false; /** * Creates a new SOS indexer for a FileSystem reader. * * @param configuration A configuration object containing the database informations.Must not be null. * @param serviceID The identifier, if there is one, of the index/service. * @param create */ public LuceneObservationIndexer(final Automatic configuration, final String serviceID, final boolean create) throws IndexingException { super(serviceID, configuration.getConfigurationDirectory(), new WhitespaceAnalyzer(Version.LUCENE_46)); final File dataDirectory = configuration.getDataDirectory(); if (dataDirectory != null && dataDirectory.exists()) { observationDirectory = new File(dataDirectory, "observations"); if (!observationDirectory.exists()) { observationDirectory.mkdir(); } observationTemplateDirectory = new File(dataDirectory, "observationTemplates"); if (!observationTemplateDirectory.exists()) { observationTemplateDirectory.mkdir(); } } else { throw new IndexingException("The data directory does not exist: "); } if (create && needCreation()) { createIndex(); } } /** * {@inheritDoc} */ @Override protected List<String> getAllIdentifiers() throws IndexingException { throw new UnsupportedOperationException("not used in this implementation"); } @Override protected Iterator<String> getIdentifierIterator() throws IndexingException { throw new UnsupportedOperationException("not used in this implementation"); } /** * {@inheritDoc} */ @Override protected Observation getEntry(final String identifier) throws IndexingException { throw new UnsupportedOperationException("not used in this implementation"); } @Override protected Iterator<Observation> getEntryIterator() throws IndexingException { throw new UnsupportedOperationException("not used in this implementation"); } @Override protected boolean useEntryIterator() { return false; } /** * {@inheritDoc} */ @Override public void createIndex() throws IndexingException { LOGGER.info("Creating lucene index for Filesystem observations please wait..."); final long time = System.currentTimeMillis(); int nbObservation = 0; int nbTemplate = 0; try { final Unmarshaller unmarshaller = SOSMarshallerPool.getInstance().acquireUnmarshaller(); final IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_46, analyzer); final IndexWriter writer = new IndexWriter(new SimpleFSDirectory(getFileDirectory()), conf); // getting the objects list and index avery item in the IndexWriter. for (File observationFile : observationDirectory.listFiles()) { Object observation = unmarshaller.unmarshal(observationFile); if (observation instanceof JAXBElement) { observation = ((JAXBElement)observation).getValue(); } if (observation instanceof Observation) { indexDocument(writer, (Observation) observation); nbObservation++; } else { LOGGER.info("The observation file " + observationFile.getName() + " does not contains an observation:" + observation); } } template = true; for (File observationFile : observationTemplateDirectory.listFiles()) { Object observation = unmarshaller.unmarshal(observationFile); if (observation instanceof JAXBElement) { observation = ((JAXBElement)observation).getValue(); } if (observation instanceof Observation) { indexDocument(writer, (Observation) observation); nbTemplate++; } else { LOGGER.info("The template observation file " + observationFile.getName() + " does not contains an observation:" + observation); } } SOSMarshallerPool.getInstance().recycle(unmarshaller); template = false; // writer.optimize(); no longer justified writer.close(); } catch (CorruptIndexException ex) { LOGGER.log(Level.SEVERE,CORRUPTED_SINGLE_MSG + "{0}", ex.getMessage()); throw new IndexingException(CORRUPTED_MULTI_MSG, ex); } catch (LockObtainFailedException ex) { LOGGER.log(Level.SEVERE,LOCK_SINGLE_MSG + "{0}", ex.getMessage()); throw new IndexingException(LOCK_MULTI_MSG, ex); } catch (IOException ex) { LOGGER.log(Level.SEVERE,IO_SINGLE_MSG + "{0}", ex.getMessage()); throw new IndexingException("IOException while indexing documents.", ex); } catch (JAXBException ex) { String msg = ex.getMessage(); if (msg == null && ex.getCause() != null) { msg = ex.getCause().getMessage(); } LOGGER.log(Level.SEVERE, "JAXB Exception while indexing: {0}", msg); throw new IndexingException("JAXBException while indexing documents.", ex); } LOGGER.info("Index creation process in " + (System.currentTimeMillis() - time) + " ms\nObservations indexed: " + nbObservation + ". Template indexed:" + nbTemplate + "."); } /** * {@inheritDoc} */ @Override protected Document createDocument(final Observation observation, final int docid) { // make a new, empty document final Document doc = new Document(); final FieldType ft = new FieldType(); ft.setIndexed(true); ft.setStored(true); doc.add(new Field("id", observation.getName().getCode(), ft)); if (observation instanceof MeasurementType) { doc.add(new Field("type", "measurement" , ft)); } else { doc.add(new Field("type", "observation" , ft)); } doc.add(new Field("procedure", ((Process)observation.getProcedure()).getHref(), ft)); doc.add(new Field("observed_property", ((Phenomenon)observation.getObservedProperty()).getName().getCode(), ft)); doc.add(new Field("feature_of_interest", ((AbstractGML)observation.getFeatureOfInterest()).getId(), ft)); try { final TemporalObject time = observation.getSamplingTime(); if (time instanceof Period) { final Period period = (Period) time; doc.add(new Field("sampling_time_begin", SOSUtils.getLuceneTimeValue(period.getBeginning().getDate()), ft)); doc.add(new Field("sampling_time_end", SOSUtils.getLuceneTimeValue(period.getEnding().getDate()), ft)); } else if (time instanceof Instant) { final Instant instant = (Instant) time; doc.add(new Field("sampling_time_begin", SOSUtils.getLuceneTimeValue(instant.getDate()), ft)); doc.add(new Field("sampling_time_end", "NULL", ft)); } else if (time != null) { LOGGER.log(Level.WARNING, "unrecognized sampling time type:{0}", time); } } catch(DataStoreException ex) { LOGGER.severe("error while indexing sampling time."); } if (template) { doc.add(new Field("template", "TRUE", ft)); } else { doc.add(new Field("template", "FALSE", ft)); } // add a default meta field to make searching all documents easy doc.add(new Field("metafile", "doc", ft)); return doc; } /** * {@inheritDoc} */ @Override protected String getIdentifier(Observation obj) { return obj.getName().getCode(); } /** * {@inheritDoc} */ @Override public void destroy() { super.destroy(); } }