/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.classloader; import java.io.File; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassDescription; import org.eclipse.persistence.tools.workbench.utility.Classpath; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; /** * This external class repository uses a URLClassLoader to load classes * on the "project" classpath. */ final class URLCLExternalClassRepository extends AbstractCLExternalClassRepository { /** * Cache the "project" classpath with all its entries * fully qualified and duplicates stripped out, including * any duplicates of entries on the "system" classpath. */ private final Classpath canonicalProjectClasspath; // ********** constructors ********** /** * Construct a class repository for the specified "project" classpath. * The "system" classpath has already been determined and cannot be changed. * Convert the classpath: fully-qualify the entries and eliminate any duplicates. */ URLCLExternalClassRepository(File[] classpath) { super(); Classpath tempClasspath = new Classpath(this.fileNames(classpath)).compressed(); Classpath completeClasspath = Classpath.completeClasspath(); this.canonicalProjectClasspath = this.removeDuplicates(completeClasspath, tempClasspath); } /** * Return an array of the names of the specified files. */ private String[] fileNames(File[] files) { int len = files.length; String[] fileNames = new String[len]; for (int i = 0; i < len; i++) { fileNames[i] = files[i].getAbsolutePath(); } return fileNames; } /** * Remove the entries in classpath2 that are already in classpath1 * and return the resulting classpath. */ private Classpath removeDuplicates(Classpath classpath1, Classpath classpath2) { Set classpathEntries1 = CollectionTools.set(classpath1.getEntries()); List fileNames = new ArrayList(); Classpath.Entry[] entries2 = classpath2.getEntries(); int len = entries2.length; for (int i = 0; i < len; i++) { Classpath.Entry entry2 = entries2[i]; if ( ! classpathEntries1.contains(entry2)) { fileNames.add(entry2.fileName()); } } return new Classpath(fileNames); } // ********** AbstractCLExternalClassRepository implementation ********** /** * @see org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassRepository#getExternalClassDescription(String) */ public ExternalClassDescription getClassDescription(String className) { // postponing suffering even more; some queries only need classes that are on the system classpath; // if the project classpath is large, buildClassDescriptions() in the superclass can hang... ExternalClassDescription ecd = SystemCLExternalClassRepository.instance().getClassDescription(className); if (ecd != null) return ecd; return super.getClassDescription(className); } /** * @see AbstractCLExternalClassRepository#buildClassDescriptions() */ Map buildClassDescriptions() { Map classDescriptions = new HashMap(20000); // let's start large // first add the "system" classes SystemCLExternalClassRepository.instance().addClassDescriptionsTo(classDescriptions); // then add the "project" classes this.addClassDescriptionsFromClasspathTo(this.canonicalProjectClasspath, classDescriptions); return classDescriptions; } /** * @see AbstractCLExternalClassRepository#buildClassLoader() */ ClassLoader buildClassLoader() { return new URLClassLoader(this.canonicalProjectClasspath.urls()); } }