All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dellroad.stuff.pobj.SpringPersistentObjectSchemaUpdater Maven / Gradle / Ivy


/*
 * Copyright (C) 2012 Archie L. Cobbs. All rights reserved.
 */

package org.dellroad.stuff.pobj;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Comparator;

import javax.xml.transform.stream.StreamSource;

import org.dellroad.stuff.schema.SchemaUpdate;
import org.dellroad.stuff.spring.BeanNameComparator;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.core.io.Resource;

/**
 * {@link PersistentObjectSchemaUpdater} optimized for use with Spring:
 * 
    *
  • {@link #getOrderingTieBreaker} is overridden to break ties by ordering updates in the same order * as they are defined in the bean factory.
  • *
  • This class implements {@link InitializingBean} and verifies all required properties are set.
  • *
  • If no updates are {@linkplain #setUpdates explicitly configured}, then all {@link SpringPersistentObjectSchemaUpdate}s * found in the containing bean factory are automatically configured; this requires that all of the schema updates * are defined in the same {@link ListableBeanFactory}.
  • *
  • The default value may be configured as an XML resource
  • *
* *

* An example of how this class can be combined with custom XML to define an updater and all its updates: *

 *  <beans xmlns="http://www.springframework.org/schema/beans"
 *    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 *    xmlns:p="http://www.springframework.org/schema/p"
 *    xsi:schemaLocation="
 *      http://www.springframework.org/schema/beans
 *        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 *
 *      <!-- Normal nested persistent object delegate. You supply the XML (un)marshaller (not shown). -->
 *      <bean id="normalDelegate" class="org.dellroad.stuff.pobj.SpringDelegate"
 *        p:marshaller-ref="marshaller" p:unmarshaller-ref="unmarshaller"/>
 *
 *      <!-- Schema updating persistent object delegate; the updates below will be auto-detected. -->
 *      <bean id="updatingDelegate" class="org.dellroad.stuff.pobj.SpringPersistentObjectSchemaUpdater"
 *        p:marshaller-ref="marshaller" p:unmarshaller-ref="unmarshaller" p:defaultXML="classpath:default.xml">
 *          <constructor-arg ref="normalDelegate"/>
 *      </bean>
 *
 *      <!-- Persistent object, configured to use our schema updating delegate -->
 *      <bean id="persistentObject" class="org.dellroad.stuff.pobj.PersistentObject"
 *        init-method="start" destroy-method="stop" p:file="/var/lib/pobj.xml" p:allowEmptyStart="true"
 *        p:numBackups="3" p:delegate-ref="updatingDelegate"/>
 *
 *      <!-- Define a default location for schema update XSL files -->
 *      <bean class="org.dellroad.stuff.pobj.SpringXSLUpdateTransformConfigurer"
 *        p:prefix="classpath:updates/" p:suffix=".xsl"/>
 *
 *      <!-- Schema update #1 with an explicitly configured XSL resource -->
 *      <bean id="update1" class="org.dellroad.stuff.pobj.SpringXSLPersistentObjectSchemaUpdate"
 *        transform="file:///usr/share/updates/update1.xsl"/>
 *
 *      <!-- Schema update #2: implicitly uses "classpath:updates/update2.xsl" -->
 *      <bean id="update2" class="org.dellroad.stuff.pobj.SpringXSLPersistentObjectSchemaUpdate"/>
 *
 *      <!-- Schema update #3: requires that update #1 be applied first -->
 *      <bean id="update3" depends-on="update1"
 *        class="org.dellroad.stuff.pobj.SpringXSLPersistentObjectSchemaUpdate"/>
 *
 *      <!-- Add more schema updates over time as needed and everything just works... -->
 *
 *  </beans>
 * 
* * @param type of the root persistent object */ public class SpringPersistentObjectSchemaUpdater extends PersistentObjectSchemaUpdater implements BeanFactoryAware, InitializingBean { private ListableBeanFactory beanFactory; private Resource defaultXML; /** * Constructor. * * @param delegate delegate that will be wrapped by this instance * @throws IllegalArgumentException if {@code delegate} is null * @see PersistentObjectSchemaUpdater#PersistentObjectSchemaUpdater */ public SpringPersistentObjectSchemaUpdater(PersistentObjectDelegate delegate) { super(delegate); } /** * Set the resource containing the default value, encoded as XML, to be used on an uninitialized persistent object. * This will override whatever default value is returned by the nested delegate. * * @param resource default database content */ public void setDefaultXML(Resource resource) { this.defaultXML = resource; } /** * Get the default value for the persistent object when no persistent file is found. * *

* The implementation in {@link SpringPersistentObjectSchemaUpdater} parses and returns the * {@linkplain #setDefaultXML default value resource}, if any; otherwise, the delegate provided * to the constructor is queried for a default value. */ @Override public T getDefaultValue() { // If no XML configured, fall back to nested delegate if (this.defaultXML == null) return this.delegate.getDefaultValue(); // Use configured XML try { this.log.info("loading default content from " + this.defaultXML.getURI()); InputStream input = this.defaultXML.getInputStream(); try { return this.delegate.deserialize( new StreamSource(new BufferedInputStream(input), this.defaultXML.getURI().toString())); } finally { try { input.close(); } catch (IOException e) { // ignore } } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new PersistentObjectException(e); } } @Override public void setBeanFactory(BeanFactory beanFactory) { if (this.beanFactory == null && beanFactory instanceof ListableBeanFactory) this.beanFactory = (ListableBeanFactory)beanFactory; } @Override @SuppressWarnings("unchecked") public void afterPropertiesSet() throws Exception { if (this.getUpdates() == null) { if (this.beanFactory == null) { throw new IllegalArgumentException("no updates explicitly configured and the containing BeanFactory" + " is not a ListableBeanFactory: " + this.beanFactory); } this.setUpdates((Collection>)(Object)this.beanFactory.getBeansOfType( SpringPersistentObjectSchemaUpdate.class).values()); } } /** * Get the preferred ordering of two updates that do not have any predecessor constraints * (including implied indirect constraints) between them. * *

* In the case no schema updates are explicitly configured, the {@link Comparator} returned by the * implementation in {@link SpringPersistentObjectSchemaUpdater} sorts updates in the same order that they appear * in the containing {@link ListableBeanFactory}. Otherwise, the * {@linkplain org.dellroad.stuff.schema.AbstractSchemaUpdater#getOrderingTieBreaker superclass method} is used. */ @Override protected Comparator> getOrderingTieBreaker() { if (this.beanFactory == null) return super.getOrderingTieBreaker(); final BeanNameComparator beanNameComparator = new BeanNameComparator(this.beanFactory); return new Comparator>() { @Override public int compare(SchemaUpdate update1, SchemaUpdate update2) { return beanNameComparator.compare(update1.getName(), update2.getName()); } }; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy