Package org.hibernate.jpa.boot.scan.spi

Source Code of org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.jpa.boot.scan.spi;

import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
import org.hibernate.jpa.boot.internal.ClassDescriptorImpl;
import org.hibernate.jpa.boot.internal.MappingFileDescriptorImpl;
import org.hibernate.jpa.boot.internal.PackageDescriptorImpl;
import org.hibernate.jpa.boot.spi.ClassDescriptor;
import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
import org.hibernate.jpa.boot.spi.PackageDescriptor;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;

/**
* @author Steve Ebersole
*/
public abstract class AbstractScannerImpl implements Scanner {
  private final ArchiveDescriptorFactory archiveDescriptorFactory;
  private final Map<URL, ArchiveDescriptorInfo> archiveDescriptorCache = new HashMap<URL, ArchiveDescriptorInfo>();

  protected AbstractScannerImpl(ArchiveDescriptorFactory archiveDescriptorFactory) {
    this.archiveDescriptorFactory = archiveDescriptorFactory;
  }

  @Override
  public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions scanOptions) {
    final ResultCollector resultCollector = new ResultCollector( scanOptions );

    if ( persistenceUnit.getJarFileUrls() != null ) {
      for ( URL url : persistenceUnit.getJarFileUrls() ) {
        final ArchiveDescriptor descriptor = buildArchiveDescriptor( url, false, scanOptions );
        final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector );
        descriptor.visitArchive( context );
      }
    }

    if ( persistenceUnit.getPersistenceUnitRootUrl() != null ) {
      final ArchiveDescriptor descriptor = buildArchiveDescriptor( persistenceUnit.getPersistenceUnitRootUrl(), true, scanOptions );
      final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector );
      descriptor.visitArchive( context );
    }

    return ScanResultImpl.from( resultCollector );
  }

  private ArchiveContext buildArchiveContext(
      PersistenceUnitDescriptor persistenceUnit,
      boolean isRoot,
      ArchiveEntryHandlers entryHandlers) {
    return new ArchiveContextImpl( persistenceUnit, isRoot, entryHandlers );
  }

  protected static interface ArchiveEntryHandlers {
    public ArchiveEntryHandler getClassFileHandler();
    public ArchiveEntryHandler getPackageInfoHandler();
    public ArchiveEntryHandler getFileHandler();
  }

  private ArchiveDescriptor buildArchiveDescriptor(URL url, boolean isRootUrl, ScanOptions scanOptions) {
    final ArchiveDescriptor descriptor;
    final ArchiveDescriptorInfo descriptorInfo = archiveDescriptorCache.get( url );
    if ( descriptorInfo == null ) {
      descriptor = archiveDescriptorFactory.buildArchiveDescriptor( url );
      archiveDescriptorCache.put(
          url,
          new ArchiveDescriptorInfo( descriptor, isRootUrl, scanOptions )
      );
    }
    else {
      validateReuse( descriptorInfo, isRootUrl, scanOptions );
      descriptor = descriptorInfo.archiveDescriptor;
    }
    return descriptor;
  }

  public static class ResultCollector
      implements ArchiveEntryHandlers,
             PackageInfoArchiveEntryHandler.Callback,
             ClassFileArchiveEntryHandler.Callback,
             NonClassFileArchiveEntryHandler.Callback {
    private final ClassFileArchiveEntryHandler classFileHandler;
    private final PackageInfoArchiveEntryHandler packageInfoHandler;
    private final NonClassFileArchiveEntryHandler fileHandler;

    private final Set<PackageDescriptor> packageDescriptorSet = new HashSet<PackageDescriptor>();
    private final Set<ClassDescriptor> classDescriptorSet = new HashSet<ClassDescriptor>();
    private final Set<MappingFileDescriptor> mappingFileSet = new HashSet<MappingFileDescriptor>();

    public ResultCollector(ScanOptions scanOptions) {
      this.classFileHandler = new ClassFileArchiveEntryHandler( scanOptions, this );
      this.packageInfoHandler = new PackageInfoArchiveEntryHandler( scanOptions, this );
      this.fileHandler = new NonClassFileArchiveEntryHandler( scanOptions, this );
    }

    @Override
    public ArchiveEntryHandler getClassFileHandler() {
      return classFileHandler;
    }

    @Override
    public ArchiveEntryHandler getPackageInfoHandler() {
      return packageInfoHandler;
    }

    @Override
    public ArchiveEntryHandler getFileHandler() {
      return fileHandler;
    }

    @Override
    public void locatedPackage(PackageDescriptor packageDescriptor) {
      if ( PackageDescriptorImpl.class.isInstance( packageDescriptor ) ) {
        packageDescriptorSet.add( packageDescriptor );
      }
      else {
        // to make sure we have proper equals/hashcode
        packageDescriptorSet.add(
            new PackageDescriptorImpl(
                packageDescriptor.getName(),
                packageDescriptor.getStreamAccess()
            )
        );
      }
    }

    @Override
    public void locatedClass(ClassDescriptor classDescriptor) {
      if ( ClassDescriptorImpl.class.isInstance( classDescriptor ) ) {
        classDescriptorSet.add( classDescriptor );
      }
      else {
        // to make sure we have proper equals/hashcode
        classDescriptorSet.add(
            new ClassDescriptorImpl(
                classDescriptor.getName(),
                classDescriptor.getStreamAccess()
            )
        );
      }
    }

    @Override
    public void locatedMappingFile(MappingFileDescriptor mappingFileDescriptor) {
      if ( MappingFileDescriptorImpl.class.isInstance( mappingFileDescriptor ) ) {
        mappingFileSet.add( mappingFileDescriptor );
      }
      else {
        // to make sure we have proper equals/hashcode
        mappingFileSet.add(
            new MappingFileDescriptorImpl(
                mappingFileDescriptor.getName(),
                mappingFileDescriptor.getStreamAccess()
            )
        );
      }
    }

    public Set<PackageDescriptor> getPackageDescriptorSet() {
      return packageDescriptorSet;
    }

    public Set<ClassDescriptor> getClassDescriptorSet() {
      return classDescriptorSet;
    }

    public Set<MappingFileDescriptor> getMappingFileSet() {
      return mappingFileSet;
    }
  }

  private static class ArchiveDescriptorInfo {
    private final ArchiveDescriptor archiveDescriptor;
    private final boolean isRoot;
    private final ScanOptions scanOptions;

    private ArchiveDescriptorInfo(
        ArchiveDescriptor archiveDescriptor,
        boolean isRoot,
        ScanOptions scanOptions) {
      this.archiveDescriptor = archiveDescriptor;
      this.isRoot = isRoot;
      this.scanOptions = scanOptions;
    }
  }

  protected void validateReuse(ArchiveDescriptorInfo descriptor, boolean root, ScanOptions options) {
    // is it really reasonable that a single url be processed multiple times?
    // for now, throw an exception, mainly because I am interested in situations where this might happen
    throw new IllegalStateException( "ArchiveDescriptor reused; can URLs be processed multiple times?" );
  }

  public static class ArchiveContextImpl implements ArchiveContext {
    private final PersistenceUnitDescriptor persistenceUnitDescriptor;
    private final boolean isRootUrl;
    private final ArchiveEntryHandlers entryHandlers;

    public ArchiveContextImpl(
        PersistenceUnitDescriptor persistenceUnitDescriptor,
        boolean isRootUrl,
        ArchiveEntryHandlers entryHandlers) {
      this.persistenceUnitDescriptor = persistenceUnitDescriptor;
      this.isRootUrl = isRootUrl;
      this.entryHandlers = entryHandlers;
    }

    @Override
    public PersistenceUnitDescriptor getPersistenceUnitDescriptor() {
      return persistenceUnitDescriptor;
    }

    @Override
    public boolean isRootUrl() {
      return isRootUrl;
    }

    @Override
    public ArchiveEntryHandler obtainArchiveEntryHandler(ArchiveEntry entry) {
      final String nameWithinArchive = entry.getNameWithinArchive();

      if ( nameWithinArchive.endsWith( "package-info.class" ) ) {
        return entryHandlers.getPackageInfoHandler();
      }
      else if ( nameWithinArchive.endsWith( ".class" ) ) {
        return entryHandlers.getClassFileHandler();
      }
      else {
        return entryHandlers.getFileHandler();
      }
    }
  }

  private static class ScanResultImpl implements ScanResult {
    private final Set<PackageDescriptor> packageDescriptorSet;
    private final Set<ClassDescriptor> classDescriptorSet;
    private final Set<MappingFileDescriptor> mappingFileSet;

    private ScanResultImpl(
        Set<PackageDescriptor> packageDescriptorSet,
        Set<ClassDescriptor> classDescriptorSet,
        Set<MappingFileDescriptor> mappingFileSet) {
      this.packageDescriptorSet = packageDescriptorSet;
      this.classDescriptorSet = classDescriptorSet;
      this.mappingFileSet = mappingFileSet;
    }

    private static ScanResult from(ResultCollector resultCollector) {
      return new ScanResultImpl(
          Collections.unmodifiableSet( resultCollector.packageDescriptorSet ),
          Collections.unmodifiableSet( resultCollector.classDescriptorSet ),
          Collections.unmodifiableSet( resultCollector.mappingFileSet )
      );
    }

    @Override
    public Set<PackageDescriptor> getLocatedPackages() {
      return packageDescriptorSet;
    }

    @Override
    public Set<ClassDescriptor> getLocatedClasses() {
      return classDescriptorSet;
    }

    @Override
    public Set<MappingFileDescriptor> getLocatedMappingFiles() {
      return mappingFileSet;
    }
  }

}
TOP

Related Classes of org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.