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

org.wisdom.framework.jpa.JPAManager Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.framework.jpa;

import com.google.common.base.Splitter;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.annotations.*;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.util.tracker.BundleTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wisdom.framework.jpa.model.Persistence;

import javax.persistence.spi.PersistenceProvider;
import javax.xml.bind.JAXB;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * The entry point of the JPA bridge.
 * This component tracks bundles and check if they contain a {@code Meta-Persistence} header. If so, is creates a
 * necessary persistence unit. By default, the tracker check for {@code META-INF/persistence.xml}
 */
@Component(immediate = true)
@Instantiate
public class JPAManager {

    /**
     * The Meta-Persistence header.
     */
    public static final String META_PERSISTENCE = "Meta-Persistence";

    /**
     * The logger.
     */
    private final static Logger LOGGER = LoggerFactory.getLogger(JPAManager.class);

    /**
     * The bundle context, used to register the tracker.
     */
    @Context
    BundleContext context;

    /**
     * The factory used to create Persistence Unit 'instances'
     */
    @Requires(filter = "(factory.name=org.wisdom.framework.jpa.PersistenceUnitComponent)")
    Factory factory;

    /**
     * Set to be sure the weaving hook is registered first.
     */
    @Requires
    JPATransformer transformer;

    /**
     * The tracked bundle.
     */
    BundleTracker bundles;


    @Validate
    void start() throws Exception {
        // Track bundles.
        bundles = new BundleTracker(context, Bundle.ACTIVE + Bundle.STARTING, null) {

            /**
             * A new bundle arrives, check whether or not it contains persistence unit.
             * @param bundle the bundle
             * @param event the event
             * @return the Persistence Bundle object if the bundle contain PU, {@code null} if none (bundle not
             * tracked)
             */
            @Override
            public PersistentBundle addingBundle(Bundle bundle, BundleEvent event) {
                try {
                    // Parse any persistence units, returns null (not tracked) when there is no persistence unit
                    return parse(bundle);
                } catch (Exception e) {
                    LOGGER.error("While parsing bundle {} for a persistence unit we encountered " +
                                    "an unexpected exception {}. This bundle (also the other persistence " +
                                    "units in this bundle) will be ignored.",
                            bundle, e.getMessage(), e);
                    //noinspection Contract
                    return null;
                }
            }

            /**
             * A bundle is leaving.
             * @param bundle the bundle
             * @param event the event
             * @param pu the persistent bundle
             */
            @Override
            public void removedBundle(Bundle bundle, BundleEvent event, PersistentBundle pu) {
                pu.destroy();
            }
        };

        bundles.open();
    }

    /**
     * Closes the tracker.
     */
    @Invalidate
    void stop() {
        bundles.close();
    }

    /**
     * Check a bundle for persistence units following the rules in the OSGi
     * spec.
     * 

* A Persistence Bundle is a bundle that specifies the Meta-Persistence * header, see Meta Persistence Header on page 439. This header refers to * one or more Persistence Descriptors in the Persistence Bundle. Commonly, * this is the META-INF/persistence.xml resource. This location is the * standard for non- OSGi environments, however an OSGi bundle can also use * other locations as well as multiple resources. Any entity classes must * originate in the bundle's JAR, it cannot come from a fragment. This * requirement is necessary to simplify enhancing entity classes. * * @param bundle the bundle to be searched * @return a Persistent Bundle or null if it has no matching persistence * units */ PersistentBundle parse(Bundle bundle) throws Exception { LOGGER.debug("Analysing bundle {}", bundle.getBundleId()); String metapersistence = bundle.getHeaders().get(META_PERSISTENCE); if (metapersistence == null || metapersistence.trim().isEmpty()) { // Check default location (except for system bundle) if (bundle.getBundleId() != 0 && bundle.getResource("META-INF/persistence.xml") != null) { // Found at the default location metapersistence = "META-INF/persistence.xml"; } else { return null; } } LOGGER.info("META_PERSISTENCE header found in bundle {} : {}", bundle.getBundleId(), metapersistence); // We can have multiple persistence units. Set set = new HashSet<>(); for (String location : Splitter.on(",").omitEmptyStrings().trimResults().splitToList(metapersistence)) { LOGGER.info("Analysing location {}", location); // Lets remember where we came from Persistence.PersistenceUnit.Properties.Property p = new Persistence.PersistenceUnit.Properties.Property(); p.setName("location"); p.setValue(location); // Try to find the resource for the persistence unit // on the classpath: getResource URL url = bundle.getResource(location); if (url == null) { LOGGER.error("Bundle {} specifies location '{}' in the Meta-Persistence header but no such" + " resource is found in the bundle at that location.", bundle, location); } else { // Parse the XML file. Persistence persistence = JAXB.unmarshal(url, Persistence.class); LOGGER.info("Parsed persistence: {}, unit {}", persistence, persistence.getPersistenceUnit()); for (Persistence.PersistenceUnit pu : persistence.getPersistenceUnit()) { if (pu.getProperties() == null) { pu.setProperties(new Persistence.PersistenceUnit.Properties()); } pu.getProperties().getProperty().add(p); set.add(pu); LOGGER.info("Adding persistence unit {}", pu); } } } // Ignore this bundle if no valid PUs if (set.isEmpty()) { LOGGER.warn("No persistence unit found in bundle {}, despite a META_PERSISTENCE header ({})", bundle.getBundleId(), metapersistence); return null; } return new PersistentBundle(bundle, set, factory); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy