/*
* Copyright 2015-2016 Cel Skeggs.
*
* This file is part of the CCRE, the Common Chicken Runtime Engine.
*
* The CCRE is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The CCRE 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 the CCRE. If not, see <http://www.gnu.org/licenses/>.
*/
package ccre.deployment;
import java.io.IOException;
import java.io.InputStream;
/**
* A built artifact, as in a collection of classes and resources stored
* somewhere in some form.
*
* For example, this could be a folder, a JAR, or really anything else.
*
* @author skeggsc
*/
public abstract class Artifact implements AutoCloseable {
/**
* Lists the class names contained in this Artifact, in the form
* <code>outer.package.inner.package.ClassName</code>.
*
* @return the array of class names.
*/
public String[] listClassNames() {
String[] in = listClassesAndResources();
int count = 0;
for (int i = 0; i < in.length; i++) {
String name = in[i];
if (name.endsWith(".class")) {
// convert resource name to class name
in[i] = name.substring(name.charAt(0) == '/' ? 1 : 0, name.length() - 6).replace('/', '.');
count++;
} else {
in[i] = null;
}
}
String[] out = new String[count];
int i = 0;
for (String name : in) {
if (name != null) {
out[i++] = name;
}
}
if (i != count) {
throw new RuntimeException("Internal error...?");
}
return out;
}
/**
* Lists the names of the resources contained in this Artifact. These are
* any files that aren't <code>.class</code> files.
*
* @return the array of resource names.
*/
public String[] listResources() {
String[] in = listClassesAndResources();
int count = 0;
for (int i = 0; i < in.length; i++) {
String name = in[i];
if (name.endsWith(".class")) {
in[i] = null;
} else {
count++;
}
}
String[] out = new String[count];
int i = 0;
for (String name : in) {
if (name != null) {
out[i++] = name;
}
}
if (i != count) {
throw new RuntimeException("Internal error...?");
}
return out;
}
/**
* Returns the list of all classes and resources, in terms of the file
* names. This could also be named <code>listFiles</code>.
*
* @return the array of filenames.
*/
protected abstract String[] listClassesAndResources();
/**
* Open an InputStream that reads the named class, which can be either in
* the form <code>package.ClassName</code> or <code>package/ClassName</code>
* .
*
* @param name the name of the class to load.
* @return an InputStream reading the classfile's data.
* @throws IOException if the resource cannot be loaded.
*/
public InputStream loadClassFile(String name) throws IOException {
return loadResource("/" + name.replace('.', '/') + ".class");
}
/**
* Open an InputStream that reads the named resource, which should be a file
* path. It may optionally start with a forward slash.
*
* @param name the file path of the resource to load, within this artifact.
* @return an InputStream reading the resource's data.
* @throws IOException if the resource cannot be loaded.
*/
public abstract InputStream loadResource(String name) throws IOException;
/**
* Coerce this artifact into a Jar, which may be optionally marked for
* preservation.
*
* See {@link Jar} for a discussion of what Jar preservation means.
*
* If this is already a Jar, we just return the Jar, possibly modified for
* preservation reasons.
*
* @param preserve if this Jar should be marked for preservation.
* @return the new (or old) Jar containing the same classes and resources as
* this artifact.
* @throws IOException if an error occurs during conversion.
*/
public Jar toJar(boolean preserve) throws IOException {
JarBuilder jb = new JarBuilder(preserve);
for (String elem : listClassNames()) {
jb.addClass(elem, loadClassFile(elem));
}
for (String elem : listResources()) {
jb.addResource(elem, loadResource(elem));
}
return jb.build();
}
public abstract void close() throws IOException;
}