it.tidalwave.metadata.spi.MetadataItemProviderSupport Maven / Gradle / Ivy
The newest version!
/***********************************************************************************************************************
*
* blueMarine Metadata - open source media workflow
* Copyright (C) 2007-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* 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.
*
***********************************************************************************************************************
*
* WWW: http://bluemarine.tidalwave.it
* SCM: https://kenai.com/hg/bluemarine~metadata-src
*
**********************************************************************************************************************/
package it.tidalwave.metadata.spi;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import it.tidalwave.util.logging.Logger;
import org.openide.loaders.DataObject;
import org.openide.util.Lookup;
import it.tidalwave.stopwatch.StopWatch;
import it.tidalwave.metadata.Metadata.FindOption;
import it.tidalwave.metadata.Metadata.NameFilter;
import it.tidalwave.metadata.Metadata.StorageType;
import it.tidalwave.metadata.Metadata.StoreOption;
import it.tidalwave.metadata.MetadataItemHolder;
/*******************************************************************************
*
* This class provides a default implementation of a provider. Concrete subclasses
* must just declare the class of the managed items in the constructor.
*
* @author Fabrizio Giudici
* @version $Id$
*
******************************************************************************/
public abstract class MetadataItemProviderSupport- implements MetadataItemProvider
-
{
private static final String CLASS = MetadataItemProviderSupport.class.getName();
private static final Logger logger = Logger.getLogger(CLASS);
/***************************************************************************
*
*
**************************************************************************/
protected static enum CreationStrategy
{
RAW
{
@Nonnull
public
- Item createItem (@Nonnull final Class
- itemClass)
throws Exception
{
return itemClass.newInstance();
}
},
ENHANCED
{
@Nonnull
public
- Item createItem (@Nonnull final Class
- itemClass)
throws Exception
{
return MetadataItemEnhancer.createEnhancedItem(itemClass.newInstance());
}
};
@Nonnull
public abstract
- Item createItem (@Nonnull final Class
- itemClass)
throws Exception;
}
@Nonnull
private final Class
- itemClass;
@Nonnull
private final CreationStrategy creationStrategy;
/***************************************************************************
*
*
**************************************************************************/
private final static Comparator
> holderSorterByLatestModificationTime =
new Comparator>()
{
public int compare (@Nonnull final MetadataItemHolder> holder1,
@Nonnull final MetadataItemHolder> holder2)
{
final Date date1 = holder1.getLatestModificationTime();
final Date date2 = holder2.getLatestModificationTime();
if (date1 == null)
{
return (date2 == null) ? 0 : +1;
}
if (date2 == null)
{
return -1;
}
return -date1.compareTo(date2);
}
};
/***************************************************************************
*
* Creates a new instance of this provider, specifying the class of the
* items it can manage.
*
* @param itemClass the class of the managed items
* @param creationStrategy the creation strategy for items
*
**************************************************************************/
public MetadataItemProviderSupport (@Nonnull final Class- itemClass,
@Nonnull final CreationStrategy creationStrategy)
{
this.itemClass = itemClass;
this.creationStrategy = creationStrategy;
}
/***************************************************************************
*
* {@inheritDoc}
*
**************************************************************************/
@Nonnull
final public Class
- getItemClass()
{
return itemClass;
}
/***************************************************************************
*
* {@inheritDoc}
*
**************************************************************************/
@Nonnull
final public List
> findOrCreateItems (@Nonnull final DataObject dataObject,
@Nonnull final FindOption ... options)
{
logger.fine("findOrCreateItems(%s, %s)", dataObject, Arrays.toString(options));
if (dataObject == null)
{
throw new IllegalArgumentException("dataObject is mandatory");
}
MetadataSpiUtils.validateOptions(options);
final List> holders = findItems(itemClass, dataObject, options);
// The new holder will have isAvailable() == false
// FIXME: have a Map and make sure that the same instance for each DataObject is returned
if (holders.isEmpty())
{
holders.add(createNewItem());
}
return holders;
}
/***************************************************************************
*
* {@inheritDoc}
*
**************************************************************************/
public int storeItem (@Nonnull final DataObject dataObject,
@Nonnull final MetadataItemHolder- holder,
@Nonnull final StoreOption ... options)
{
logger.fine("storeItem(%s, %s, %s)", dataObject, holder, Arrays.toString(options));
if (dataObject == null)
{
throw new IllegalArgumentException("dataObject is mandatory");
}
if (holder == null)
{
throw new IllegalArgumentException("holder is mandatory");
}
final NameFilter sinkNames = MetadataSpiUtils.findOption(options, NameFilter.ANY_NAME, NameFilter.class);
final StorageType storageType = MetadataSpiUtils.findOption(options, StorageType.ANY_TYPE, StorageType.class);
int result = 0;
for (final MetadataItemSink
- sink : findMetadataItemSinks(itemClass))
{
if (sinkNames.matches(sink.getName()) && storageType.includes(sink.getType()))
{
try
{
sink.storeMetadataItem(dataObject, holder, options);
result++;
}
catch (Throwable t)
{
// FIXME! This is important to pass RetryException from TxTask.
// It's important to have the retry logic to work for a LockException.
// But it's not good that we depend on that, here we should know nothing
// about JPA!
throw (t instanceof RuntimeException) ? (RuntimeException)t : new RuntimeException(t);
// logger.throwing(CLASS, "storeItem()", t);
// logger.warning("storeItem() threw exception: %s", sink));
}
}
}
return result;
}
/***************************************************************************
*
* Subclasses must implement this method to return a new
* {@link MetadataHolder} for the new item. It is mandatory that the
* property {@link MetadataHolder#getLatestModificationTime()} is initially
* null for the returned item.
*
* @param item the new item
* @return a new holder for the item
*
**************************************************************************/
@Nonnull
protected abstract MetadataItemHolder
- createMetadataHolder (@Nonnull final Item item);
/***************************************************************************
*
* Returns a sorted list of holders retrieved by some sources. The result
* can be an empty list if nothing is found. The list is sorted by
* descending {@link MetadataHolder#getLatestModificationTime()}.
*
* @param itemClass the type of metadata item to search
* @param dataObject the bound object
* @param options some options
* @return a list of holders
*
**************************************************************************/
@Nonnull
protected static
- List
> findItems (@Nonnull final Class- itemClass,
@Nonnull final DataObject dataObject,
@Nonnull final FindOption ... options)
{
logger.fine("findItems(%s, %s, %s)", itemClass, dataObject, Arrays.toString(options));
@Nonnull
final StorageType sourceType = MetadataSpiUtils.findOption(options, StorageType.ANY_TYPE, StorageType.class);
final List
> result = new ArrayList>();
for (final MetadataItemSource- source : findMetadataItemSources(itemClass))
{
if (sourceType.includes(source.getType()))
{
try
{
result.addAll(source.loadMetadataItems(dataObject));
}
// Prevent a failing source from disrupting the whole operation
catch (Throwable t)
{
logger.throwing(CLASS, "findItems()", t);
logger.warning("findItems() threw exception %s: %s", t, source);
}
}
}
Collections.sort(result, holderSorterByLatestModificationTime);
return result;
}
/***************************************************************************
*
* Returns a list of {@link MetadataItemSource}s suitable for the given
* item type.
*
* @param itemClass the metadata item type
* @return a list of suitable {@link MetadataItemSource}s
*
**************************************************************************/
@Nonnull
protected static
- List
> findMetadataItemSources (@Nonnull final Class- itemClass)
{
final List
> result = new ArrayList>();
for (final MetadataItemSource- source : Lookup.getDefault().lookupAll(MetadataItemSource.class))
{
if (source.getItemClass().equals(itemClass))
{
result.add(source);
}
}
logger.finest(">>>> sources for %s: %s", itemClass, result);
return result;
}
/***************************************************************************
*
* Returns a list of {@link MetadataItemSink}s suitable for the given
* item type.
*
* @param itemClass the metadata item type
* @return a list of suitable {@link MetadataItemSink}s
*
**************************************************************************/
@Nonnull
private static
- List
> findMetadataItemSinks (@Nonnull final Class- itemClass)
{
final List
> result = new ArrayList>();
for (final MetadataItemSink- sink : Lookup.getDefault().lookupAll(MetadataItemSink.class))
{
if (sink.getItemClass().isAssignableFrom(itemClass))
{
result.add(sink);
}
}
logger.finest(">>>> sinks for %s: %s", itemClass, result);
return result;
}
/***************************************************************************
*
*
**************************************************************************/
@Nonnull
private MetadataItemHolder
- createNewItem()
{
final StopWatch stopWatch = StopWatch.create(MetadataItemProviderSupport.class, "createNewItem/" + itemClass.getName());
try
{
final MetadataItemHolder
- holder = createMetadataHolder(creationStrategy.createItem(itemClass));
if (holder.getLatestModificationTime() != null)
{
throw new AssertionError("MetadataHolders created by createMetadataHolder() must have getLatestModificationTime() == null");
}
return holder;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
finally
{
stopWatch.stop();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy