io.qt.internal.LibraryBundle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qtjambi Show documentation
Show all versions of qtjambi Show documentation
QtJambi base module containing QtCore, QtGui and QtWidgets.
/****************************************************************************
**
** Copyright (C) 2009-2024 Dr. Peter Droste, Omix Visualization GmbH & Co. KG. All rights reserved.
**
** This file is part of Qt Jambi.
**
** $BEGIN_LICENSE$
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** $END_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
package io.qt.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import io.qt.QLibraryNotLoadedError;
import io.qt.core.QPair;
/**
* @hidden
*/
final class LibraryBundle {
private static final Map libraryMap = Collections.synchronizedMap(new HashMap());
private LibraryBundle(){}
static void deployQml() {
for(Library e : new ArrayList<>(libraryMap.values())) {
if(e.isLoaded() && e.isQmlExtracting()) {
try {
e.extractQml();
} catch (Throwable e1) {
throw new QLibraryNotLoadedError("Unable to extract library "+e.getName(), e1);
}
}
}
}
static Library findLibrary(String lib) {
Library entry = libraryMap.get(lib);
while(entry instanceof Symlink) {
String target = ((Symlink)entry).getTarget();
if(target.startsWith("lib/") || target.startsWith("bin/")) {
target = target.substring(4);
}
Library eTarget = libraryMap.get(target);
if(eTarget==null)
break;
else
entry = eTarget;
}
return entry;
}
static void deploy(String path) {
Library entry = libraryMap.get(path);
if(entry!=null) {
try {
entry.extract();
} catch (Throwable e) {
Logger.getLogger("io.qt.internal").throwing(LibraryUtility.class.getName(), "extracting library", e);
}
}
}
private String compiler;
private Configuration configuration;
private String system;
private String version;
private String module;
private URL url;
private File extractionDir;
private boolean hasPluginPaths;
private boolean hasQmlPaths;
private boolean hasTrPaths;
private boolean hasSourcePaths;
private boolean isDebuginfo;
private List libraries;
private List> files;
private List qmlLibraries;
private void addQmlLibrary(String name) {
if (qmlLibraries == null)
qmlLibraries = new ArrayList<>();
qmlLibraries.add(name);
}
private void addLibrary(Library e) {
if (libraries == null)
libraries = new ArrayList<>();
libraries.add(e);
}
private void addFile(String direntAsString, boolean isExecutable) {
if (files == null)
files = new ArrayList<>();
files.add(new QPair<>(direntAsString, isExecutable));
}
URL url() {
return url;
}
public static LibraryBundle read(URL sourceUrl) throws ParserConfigurationException, IOException, SAXException {
LibraryBundle depl = new LibraryBundle();
depl.url = sourceUrl;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc;
try(InputStream inStream = sourceUrl.openStream()){
doc = builder.parse(inStream);
}
depl.system = doc.getDocumentElement().getAttribute("system");
if (depl.system == null || depl.system.length() == 0) {
throw new SpecificationException(" element missing required attribute 'system'");
} else if (!depl.system.equals(LibraryUtility.osArchName)) {
throw new WrongSystemException(String.format("Expected version: %1$s, found: %2$s.", LibraryUtility.osArchName, depl.system));
}
depl.version = doc.getDocumentElement().getAttribute("version");
if (depl.version == null || depl.version.isEmpty())
throw new SpecificationException(" element missing required attribute 'version'");
depl.module = doc.getDocumentElement().getAttribute("module");
depl.compiler = doc.getDocumentElement().getAttribute("compiler");
if(depl.compiler!=null && depl.compiler.isEmpty())
depl.compiler = null;
if(depl.module!=null && depl.module.isEmpty())
depl.module = null;
String configuration = doc.getDocumentElement().getAttribute("configuration");
if("debuginfo".equals(configuration)) {
depl.configuration = LibraryBundle.Configuration.Release;
depl.isDebuginfo = true;
}else if(LibraryBundle.Configuration.Release.toString().equalsIgnoreCase(configuration))
depl.configuration = LibraryBundle.Configuration.Release;
else if(LibraryBundle.Configuration.Debug.toString().equalsIgnoreCase(configuration))
depl.configuration = LibraryBundle.Configuration.Debug;
else
depl.configuration = LibraryBundle.Configuration.Release;
NodeList childNodes = doc.getDocumentElement().getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if(child instanceof Element) {
Element element = (Element)child;
String elementName = element.getLocalName();
if(elementName==null)
elementName = element.getNodeName();
String name = element.getAttribute("name");
if (name==null || name.isEmpty())
throw new SpecificationException(String.format("<%1$s> element missing required attribute \"name\"", elementName));
if(name.startsWith("qml/")) {
depl.hasQmlPaths = true;
}else if(name.startsWith("plugins/")) {
depl.hasPluginPaths = true;
}else if(name.startsWith("translations/")) {
depl.hasTrPaths = true;
}else if(name.startsWith("sources/")) {
depl.hasSourcePaths = true;
}
Library libraryEntry;
switch(elementName) {
case "library":
libraryEntry = new Library(name, depl);
depl.addLibrary(libraryEntry);
if(name.startsWith("plugins/containeraccess/")) {
if (libraryMap.get(name)==null)
libraryMap.put(name, libraryEntry);
}else {
if(name.startsWith("lib/") || name.startsWith("bin/"))
name = name.substring(4);
Library old = libraryMap.get(name);
if (old != null && !old.depl.url.equals(sourceUrl)) {
throw new SpecificationException(String.format(
" '%1$s' is duplicated. Present in both '%2$s' and '%3$s'.",
name, sourceUrl, old.depl.url));
}
if (old==null)
libraryMap.put(name, libraryEntry);
}
break;
case "qmllib":
depl.addQmlLibrary(name);
break;
case "file":
depl.addFile(name, "true".equalsIgnoreCase(element.getAttribute("executable")));
break;
case "symlink":
String target = element.getAttribute("target");
if(target==null || target.isEmpty())
throw new SpecificationException(" element missing required attribute \"target\"");
libraryEntry = new Symlink(name, target, depl);
depl.addLibrary(libraryEntry);
if(name.startsWith("lib/") || name.startsWith("bin/"))
name = name.substring(4);
if (libraryMap.get(name)==null)
libraryMap.put(name, libraryEntry);
break;
}
}
}
return depl;
}
public File extractionDir() {
return extractionDir;
}
public void setExtractionDir(File extractionDir) throws MalformedURLException {
this.extractionDir = extractionDir;
}
List libraries() {
return libraries == null ? Collections.emptyList() : Collections.unmodifiableList(libraries);
}
public List> files() {
return files == null ? Collections.emptyList() : Collections.unmodifiableList(files);
}
public List qmlLibraries() {
return qmlLibraries==null ? Collections.emptyList() : Collections.unmodifiableList(qmlLibraries);
}
public String compiler() {
return compiler;
}
Configuration configuration() {
return configuration;
}
public String version() {
return version;
}
public String module() {
return module;
}
public boolean hasPluginPaths() {
return hasPluginPaths;
}
public boolean hasQmlPaths() {
return hasQmlPaths;
}
public boolean hasTrPaths() {
return hasTrPaths;
}
static class Library {
private final String name;
private final LibraryBundle depl;
Library(String name, LibraryBundle depl) {
super();
this.name = name;
this.depl = depl;
}
URL source() {
return depl.url;
}
LibraryBundle bundle() {
return depl;
}
public String getName() {
return name;
}
public File extractionPath() {
if(depl.extractionDir() == null)
return null;
return new File(depl.extractionDir(), name);
}
private boolean loaded;
public boolean isExtracting() {
synchronized(this.extractionFunctions) {
return !extractionFunctions.isEmpty();
}
}
public boolean isQmlExtracting() {
synchronized(this.qmlExtractionFunctions) {
return !qmlExtractionFunctions.isEmpty();
}
}
public boolean isLoaded() {
return loaded;
}
void setLoaded(boolean loaded) {
this.loaded = loaded;
if(loaded) {
// synchronized(this.extractionFunctions) {
// extractionFunctions.clear();
// }
// synchronized(this.qmlExtractionFunctions) {
// qmlExtractionFunctions.clear();
// }
}
}
interface ExtractionFunction{
void extract() throws Throwable;
}
private final List extractionFunctions = new LinkedList<>();
private final List qmlExtractionFunctions = new LinkedList<>();
void addExtractionFunction(ExtractionFunction loadFunction) {
addExtractionFunctions(Collections.singletonList(loadFunction));
}
void addQmlExtractionFunction(ExtractionFunction loadFunction) {
addQmlExtractionFunctions(Collections.singletonList(loadFunction));
}
void addExtractionFunctions(Collection loadFunctions) {
synchronized(this.extractionFunctions) {
if(this.extractionFunctions.isEmpty()) {
this.extractionFunctions.add(()->Logger.getLogger("io.qt.internal").log(Level.FINEST, ()->String.format("extracting %1$s", name)));
}
this.extractionFunctions.addAll(loadFunctions);
}
}
void addQmlExtractionFunctions(Collection loadFunctions) {
synchronized(this.qmlExtractionFunctions) {
if(this.qmlExtractionFunctions.isEmpty()) {
this.qmlExtractionFunctions.add(()->Logger.getLogger("io.qt.internal").log(Level.FINEST, ()->String.format("extracting qml of %1$s", name)));
}
this.qmlExtractionFunctions.addAll(loadFunctions);
}
}
public void extract() throws Throwable {
ExtractionFunction first = null;
while(true){
synchronized(this.extractionFunctions) {
this.extractionFunctions.remove(first);
if(this.extractionFunctions.isEmpty())
break;
else
first = this.extractionFunctions.get(0);
}
first.extract();
}
}
public void extractQml() throws Throwable {
ExtractionFunction first = null;
while(true){
synchronized(this.qmlExtractionFunctions) {
this.qmlExtractionFunctions.remove(first);
if(this.qmlExtractionFunctions.isEmpty())
break;
else
first = this.qmlExtractionFunctions.get(0);
}
first.extract();
}
}
}
static class Symlink extends Library {
Symlink(String name, String target, LibraryBundle depl) {
super(name, depl);
this.target = target;
}
private final String target;
public String getTarget() {
return target;
}
}
/**
* Enum for defining whether Qt is build in Release or Debug.
*/
enum Configuration {
Release,
Debug
}
static class SpecificationException extends RuntimeException {
private static final long serialVersionUID = 1L;
SpecificationException(String msg) {
super(msg);
}
}
static class WrongSystemException extends SpecificationException {
private static final long serialVersionUID = 1L;
WrongSystemException(String msg) {
super(msg);
}
}
static class WrongBuildException extends SpecificationException {
private static final long serialVersionUID = 1L;
WrongBuildException(String msg) {
super(msg);
}
}
static class WrongConfigurationException extends SpecificationException {
private static final long serialVersionUID = 1L;
WrongConfigurationException(String msg) {
super(msg);
}
}
static class WrongVersionException extends SpecificationException {
private static final long serialVersionUID = 1L;
WrongVersionException(String msg) {
super(msg);
}
}
public boolean hasSourcePaths() {
return hasSourcePaths;
}
public boolean isDebuginfo() {
return isDebuginfo;
}
}