Java tutorial
package hu.unideb.inf.rdfizers.rpm; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.EnumMap; import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import org.apache.commons.codec.binary.Base64; import com.hp.hpl.jena.rdf.model.Alt; import com.hp.hpl.jena.rdf.model.Bag; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Seq; import com.hp.hpl.jena.vocabulary.DC; import com.hp.hpl.jena.vocabulary.DCTerms; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; import com.hp.hpl.jena.vocabulary.XSD; /** * Class to build <a href="http://jena.apache.org/">Apache Jena</a> RDF models from RPM package files. * * @see <a href="http://rpm5.org/docs/rpm-guide.html">RPM Guide</a> */ public class ModelBuilder { private static Logger logger = LoggerFactory.getLogger(ModelBuilder.class); private static final String FOAF_NS = "http://xmlns.com/foaf/0.1/"; private static final String RPM_NS = "http://purl.org/net/vocabulary/rpm#"; private static Pattern pattern = Pattern .compile("^(.*)<([\\p{Alnum}._%+-]+@[\\p{Alnum}.-]+\\.[\\p{Alpha}]{2,4})>$"); private DataInputStream in; private String uri; private int bytesRead = 0; private Model model = ModelFactory.createDefaultModel(); { model.setNsPrefix("xsd", XSD.getURI()); model.setNsPrefix("rpm", RPM_NS); model.setNsPrefix("dc", DC.getURI()); model.setNsPrefix("dcterms", DCTerms.getURI()); model.setNsPrefix("foaf", FOAF_NS); } private Resource rpmResource; private ModelBuilder(InputStream is, String uri) { in = new DataInputStream(is); this.uri = uri; } /** * Consumes the RPM lead. */ private void processLead() throws IOException { if (in.readInt() != 0xedabeedb) throw new IOException("Not an RPM file"); final int majorVersion = in.readUnsignedByte(); final int minorVersion = in.readUnsignedByte(); logger.debug("Version: {}.{}", majorVersion, minorVersion); final short type = in.readShort(); if (type != 0 && type != 1) throw new IOException("Invalid RPM lead"); logger.debug("Type: {}", (type == 0 ? "binary" : "source")); final short archNum = in.readShort(); logger.debug("Architecture: {}", archNum); in.skipBytes(66); final short osNum = in.readShort(); logger.debug("OS: {}", osNum); final short signatureType = in.readShort(); logger.debug("Signature type: {}", signatureType); in.skipBytes(16); bytesRead += 96; } /** * Utility class to store an RPM index entry. */ private static class IndexEntry { public int tag; public int type; public int offset; public int count; public IndexEntry(int tag, int type, int offset, int count) { this.tag = tag; this.type = type; this.offset = offset; this.count = count; } public String toString() { return String.format("[tag=%d type=%d offset=%d count=%d]", tag, type, offset, count); } } /** * Processes an RPM header structure (signature or header). */ private Map processHeaderStructure(HeaderStructureType type) throws IOException { if (bytesRead % 8 != 0) { // header structure must be aligned 8 byte boundary in.skipBytes(8 - (bytesRead % 8)); bytesRead += 8 - (bytesRead % 8); } if (in.readUnsignedByte() != 0x8e || in.readUnsignedByte() != 0xad || in.readUnsignedByte() != 0xe8) throw new IOException("Invalid RPM header structure"); in.skipBytes(5); bytesRead += 8; final int num = in.readInt(); bytesRead += 4; logger.debug("Number of index entries: {}", num); final int size = in.readInt(); bytesRead += 4; logger.debug("Store size: {}", size); // read index entries IndexEntry[] index = new IndexEntry[num]; for (int i = 0; i < num; ++i) { index[i] = new IndexEntry(in.readInt(), in.readInt(), in.readInt(), in.readInt()); bytesRead += 16; } // read store byte[] store = new byte[size]; in.readFully(store); bytesRead += size; switch (type) { case SIGNATURE: { Map<SignatureTag, Object> map = new EnumMap<SignatureTag, Object>(SignatureTag.class); for (int i = 0; i < index.length; ++i) { SignatureTag tag = SignatureTag.get(index[i].tag); if (tag != null) { if (HeaderType.get(index[i].type) != tag.getType()) throw new IOException("Invalid RPM signature"); Object value = getValueFromStore(index[i], store); map.put(tag, value); } else logger.warn("Skipping tag in signature: {}", index[i].tag); } return map; } case HEADER: { Map map = new EnumMap<HeaderTag, Object>(HeaderTag.class); for (int i = 0; i < index.length; ++i) { HeaderTag tag = HeaderTag.get(index[i].tag); if (tag != null) { if (HeaderType.get(index[i].type) != tag.getType()) { throw new IOException("Invalid RPM header"); } Object value = getValueFromStore(index[i], store); map.put(tag, value); } else logger.warn("Skipping tag in header: {}", index[i].tag); } return map; } } return null; } /** * Gets an INT16 value from the store. */ private short getShort(byte[] store, int offset) { int b1 = 0xff & store[offset]; int b2 = 0xff & store[offset + 1]; int intValue = (b1 << 8) + (b2 << 0); return (short) intValue; } /** * Gets an INT32 value from the store. */ private int getInt(byte[] store, int offset) { int b1 = 0xff & store[offset]; int b2 = 0xff & store[offset + 1]; int b3 = 0xff & store[offset + 2]; int b4 = 0xff & store[offset + 3]; int intValue = (b1 << 24) + (b2 << 16) + (b3 << 8) + (b4 << 0); return intValue; } /** * Gets the value from the store that belongs to the entry. */ private Object getValueFromStore(IndexEntry entry, byte[] store) throws UnsupportedEncodingException { switch (HeaderType.get(entry.type)) { case NULL: { return null; } case CHAR: { // We can simply omit this type because it is not used currently (none of the documented signature tags or header tags uses this type) break; } case INT8: { byte[] byteArray = new byte[entry.count]; System.arraycopy(store, entry.offset, byteArray, 0, entry.count); return byteArray; } case INT16: { short[] shortArray = new short[entry.count]; for (int i = 0, j = entry.offset; i < entry.count; ++i, j += 2) { shortArray[i] = getShort(store, j); } return shortArray; } case INT32: { int[] intArray = new int[entry.count]; for (int i = 0, j = entry.offset; i < entry.count; ++i, j += 4) { intArray[i] = getInt(store, j); } return intArray; } case INT64: { // We can simply omit this type because it is not used (not supported) return null; } case STRING: { // UTF-8 character encoding is assumed int i; for (i = entry.offset; store[i] != 0; ++i) ; return new String(store, entry.offset, i - entry.offset, "UTF-8"); } case BIN: { byte[] byteArray = new byte[entry.count]; System.arraycopy(store, entry.offset, byteArray, 0, entry.count); return byteArray; } case STRING_ARRAY: { // UTF-8 character encoding is assumed String[] stringArray = new String[entry.count]; int i = entry.offset - 1; int start; for (int j = 0; j < entry.count; ++j) { for (start = ++i; store[i] != 0; ++i) ; stringArray[j] = new String(store, start, i - start, "UTF-8"); } return stringArray; } case I18NSTRING: { // TODO: the use of this type needs clarification, until then treat it as an array of UTF-8 encoded strings String[] stringArray = new String[entry.count]; int i = entry.offset - 1; int start; for (int j = 0; j < entry.count; ++j) { for (start = ++i; store[i] != 0; ++i) ; stringArray[j] = new String(store, start, i - start, "UTF-8"); } return stringArray; } } return null; } private void process() throws IOException { processLead(); Map signature = processHeaderStructure(HeaderStructureType.SIGNATURE); Map header = processHeaderStructure(HeaderStructureType.HEADER); process(signature, header); } /** * Processes the specified RPM package file. * * @param is the stream from which the RPM package file is to be read * @param uri the URI of the RPM package file * @throws IOException if an I/O error occurs * @return an RDF model that stores metadata obtained from the RPM package file */ public static Model process(InputStream is, String uri) throws IOException { ModelBuilder main = new ModelBuilder(is, uri); main.process(); return main.model; } /** * Processes the specified RPM package file. * * @param file the RPM package file * @throws IOException if an I/O error occurs * @return an RDF model that stores metadata obtained from the RPM package file */ public static Model process(File file) throws IOException { return process(new FileInputStream(file), file.toURI().toURL().toString()); } /** * Processes the specified RPM package file. * * @param fileName filename of the RPM package file * @throws IOException if an I/O error occurs * @return an RDF model that stores metadata obtained from the RPM package file */ public static Model process(String fileName) throws IOException { return process(new File(fileName)); } /** * Processes the specified RPM package file. * * @param url URL of the RPM package file * @throws IOException if an I/O error occurs * @return an RDF model that stores metadata obtained from the RPM package file */ public static Model process(URL url) throws IOException { return process(url.openStream(), url.toString()); } /** * An enumeration of the header structure types. */ private static enum HeaderStructureType { SIGNATURE, HEADER }; /** * An enumeration of the available header types. */ private static enum HeaderType { NULL, CHAR, INT8, INT16, INT32, INT64, STRING, BIN, STRING_ARRAY, I18NSTRING; /** * Returns the appropriate header type identified by the supplied value. */ public static HeaderType get(int value) { try { return values()[value]; } catch (IndexOutOfBoundsException e) { return null; } } } /** * Interface implemented by header tags and signature tags. */ private static interface Tag { /** * Returns the type of the tag. */ public HeaderType getType(); /** * Returns an appropriate name that can be used in XML documents to identify the tag. */ public String toXML(); } /** * An enumeration of the documented RPM signature tags. */ private static enum SignatureTag implements Tag { HEADERSIGNATURES(62, HeaderType.BIN), RSA(268, HeaderType.BIN), SHA1(269, HeaderType.STRING), SIGSIZE(1000, HeaderType.INT32), PGP(1002, HeaderType.BIN), MD5(1004, HeaderType.BIN), GPG(1005, HeaderType.BIN), PAYLOADSIZE(1007, HeaderType.INT32), SHA1HEADER(1010, HeaderType.BIN), DSAHEADER(1011, HeaderType.BIN), RSAHEADER(1012, HeaderType.BIN); private static final HashMap<Integer, SignatureTag> map = new HashMap<Integer, SignatureTag>(); static { for (SignatureTag tag : values()) { map.put(tag.value, tag); } } private int value; private HeaderType type; private SignatureTag(int value, HeaderType type) { this.value = value; this.type = type; } public HeaderType getType() { return type; } public String toXML() { return name().toLowerCase(); } /** * Returns the appropriate signature tag identified by the supplied value. */ public static SignatureTag get(int value) { return map.get(value); } } private static enum HeaderTag implements Tag { HEADERI18NTABLE(100, HeaderType.STRING_ARRAY), NAME(1000, HeaderType.STRING), VERSION(1001, HeaderType.STRING), RELEASE(1002, HeaderType.STRING), EPOCH(1003, HeaderType.INT32), SUMMARY(1004, HeaderType.I18NSTRING), DESCRIPTION(1005, HeaderType.I18NSTRING), BUILDTIME(1006, HeaderType.INT32), BUILDHOST(1007, HeaderType.STRING), SIZE(1009, HeaderType.INT32), DISTRIBUTION(1010, HeaderType.STRING), VENDOR(1011, HeaderType.STRING), LICENSE(1014, HeaderType.STRING), PACKAGER(1015, HeaderType.STRING), GROUP(1016, HeaderType.I18NSTRING), URL( 1020, HeaderType.STRING), OS(1021, HeaderType.STRING), ARCH(1022, HeaderType.STRING), SOURCERPM(1044, HeaderType.STRING), FILEVERIFYFLAGS( 1045, HeaderType.INT32), ARCHIVESIZE( 1046, HeaderType.INT32), RPMVERSION( 1064, HeaderType.STRING), CHANGELOGTIME( 1080, HeaderType.INT32), CHANGELOGNAME( 1081, HeaderType.STRING_ARRAY), CHANGELOGTEXT( 1082, HeaderType.STRING_ARRAY), COOKIE( 1094, HeaderType.STRING), OPTFLAGS( 1122, HeaderType.STRING), PAYLOADFORMAT( 1124, HeaderType.STRING), PAYLOADCOMPRESSOR( 1125, HeaderType.STRING), PAYLOADFLAGS( 1126, HeaderType.STRING), RHNPLATFORM( 1131, HeaderType.STRING), PLATFORM( 1132, HeaderType.STRING), PREINPROG(1085, HeaderType.STRING), POSTINPROG(1086, HeaderType.STRING), PREUNPROG(1087, HeaderType.STRING), POSTUNPROG(1088, HeaderType.STRING), OLDFILENAMES(1027, HeaderType.STRING_ARRAY), FILESIZES(1028, HeaderType.INT32), FILEMODES(1030, HeaderType.INT16), FILERDEVS(1033, HeaderType.INT16), FILEMTIMES(1034, HeaderType.INT32), FILEMD5S( 1035, HeaderType.STRING_ARRAY), FILELINKTOS(1036, HeaderType.STRING_ARRAY), FILEFLAGS(1037, HeaderType.INT32), FILEUSERNAME(1039, HeaderType.STRING_ARRAY), FILEGROUPNAME(1040, HeaderType.STRING_ARRAY), FILEDEVICES(1095, HeaderType.INT32), FILEINODES( 1096, HeaderType.INT32), FILELANGS(1097, HeaderType.STRING_ARRAY), DIRINDEXES(1116, HeaderType.INT32), BASENAMES(1117, HeaderType.STRING_ARRAY), DIRNAMES(1118, HeaderType.STRING_ARRAY), FILECOLORS( 1140, HeaderType.INT32), FILECLASS( 1141, HeaderType.INT32), CLASSDICT( 1142, HeaderType.STRING_ARRAY), FILEDEPENDSX( 1143, HeaderType.INT32), FILEDEPENDSN( 1144, HeaderType.INT32), DEPENDSDICT( 1145, HeaderType.INT32), PROVIDENAME(1047, HeaderType.STRING_ARRAY), REQUIREFLAGS(1048, HeaderType.INT32), REQUIRENAME(1049, HeaderType.STRING_ARRAY), REQUIREVERSION(1050, HeaderType.STRING_ARRAY), CONFLICTFLAGS(1053, HeaderType.INT32), CONFLICTNAME(1054, HeaderType.STRING_ARRAY), CONFLICTVERSION(1055, HeaderType.STRING_ARRAY), OBSOLETENAME(1090, HeaderType.STRING_ARRAY), PROVIDEFLAGS( 1112, HeaderType.INT32), PROVIDEVERSION(1113, HeaderType.STRING_ARRAY), OBSOLETEFLAGS(1114, HeaderType.INT32), OBSOLETEVERSION(1115, HeaderType.STRING_ARRAY); private static final HashMap<Integer, HeaderTag> map = new HashMap<Integer, HeaderTag>(); static { for (HeaderTag tag : values()) { map.put(tag.value, tag); } } private int value; private HeaderType type; private HeaderTag(int value, HeaderType type) { this.value = value; this.type = type; } public HeaderType getType() { return type; } public String toXML() { return name().toLowerCase(); } /** * Returns the appropriate header tag identified by the supplied value. */ public static HeaderTag get(int value) { return map.get(value); } } private void process(Map signature, Map header) { rpmResource = model.createResource(uri); rpmResource.addProperty(RDF.type, model.createResource(RPM_NS + "Package")); // serialize these signature tags process(signature, EnumSet.of(SignatureTag.GPG, SignatureTag.MD5, SignatureTag.PGP, SignatureTag.PAYLOADSIZE, SignatureTag.RSA, SignatureTag.SHA1)); // process URL if (header.containsKey(HeaderTag.URL)) { rpmResource.addProperty(model.createProperty(RPM_NS, "url"), model.createResource((String) header.get(HeaderTag.URL))); } // process build time if (header.containsKey(HeaderTag.BUILDTIME)) { final int seconds = ((int[]) header.get(HeaderTag.BUILDTIME))[0]; rpmResource.addProperty(model.createProperty(RPM_NS, "buildtime"), model.createTypedLiteral(toDateTime(seconds).toString(), XSD.dateTime.getURI())); } // process these header tags process(header, EnumSet.of(HeaderTag.ARCH, HeaderTag.ARCHIVESIZE, HeaderTag.BUILDHOST, HeaderTag.DESCRIPTION, HeaderTag.DISTRIBUTION, HeaderTag.EPOCH, HeaderTag.GROUP, HeaderTag.LICENSE, HeaderTag.NAME, HeaderTag.OPTFLAGS, HeaderTag.OS, HeaderTag.PACKAGER, HeaderTag.PAYLOADCOMPRESSOR, HeaderTag.PAYLOADFORMAT, HeaderTag.PLATFORM, HeaderTag.RELEASE, HeaderTag.RHNPLATFORM, HeaderTag.RPMVERSION, HeaderTag.SIZE, HeaderTag.SOURCERPM, HeaderTag.SUMMARY, HeaderTag.VENDOR, HeaderTag.VERSION)); // process required capabilities if (header.containsKey(HeaderTag.REQUIRENAME)) process("depends", (String[]) header.get(HeaderTag.REQUIRENAME), (String[]) header.get(HeaderTag.REQUIREVERSION), (int[]) header.get(HeaderTag.REQUIREFLAGS)); // process provided capabilities if (header.containsKey(HeaderTag.PROVIDENAME)) process("provides", (String[]) header.get(HeaderTag.PROVIDENAME), (String[]) header.get(HeaderTag.PROVIDEVERSION), (int[]) header.get(HeaderTag.PROVIDEFLAGS)); // process conflicts if (header.containsKey(HeaderTag.CONFLICTNAME)) process("conflicts", (String[]) header.get(HeaderTag.PROVIDENAME), (String[]) header.get(HeaderTag.PROVIDEVERSION), (int[]) header.get(HeaderTag.PROVIDEFLAGS)); // process obsoletes if (header.containsKey(HeaderTag.OBSOLETENAME)) process("conflicts", (String[]) header.get(HeaderTag.OBSOLETENAME), (String[]) header.get(HeaderTag.OBSOLETEVERSION), (int[]) header.get(HeaderTag.OBSOLETEFLAGS)); // process file information processFiles(header); // serialize change log processChangeLog(header); } private void process(String property, String[] name, String[] version, int[] flags) { final Property p = model.createProperty(RPM_NS, property); for (int i = 0; i < name.length; ++i) { Resource capability = model.createResource(); capability.addProperty(RDF.type, model.createResource(RPM_NS + "Capability")); capability.addProperty(model.createProperty(RPM_NS, "name"), name[i]); if (!version[i].isEmpty()) { capability.addProperty(model.createProperty(RPM_NS, getVersionPropertyName(flags[i])), version[i]); } rpmResource.addProperty(p, capability); } } private void processFiles(Map header) { String[] fileNames = null; if (header.containsKey(HeaderTag.OLDFILENAMES)) { // file names are not compressed fileNames = (String[]) header.get(HeaderTag.OLDFILENAMES); } else if (header.containsKey(HeaderTag.BASENAMES) && header.containsKey(HeaderTag.DIRNAMES) && header.containsKey(HeaderTag.DIRINDEXES)) { // file names are compressed String[] baseNames = (String[]) header.get(HeaderTag.BASENAMES); String[] dirNames = (String[]) header.get(HeaderTag.DIRNAMES); int[] dirIndexes = (int[]) header.get(HeaderTag.DIRINDEXES); fileNames = new String[baseNames.length]; for (int i = 0; i < fileNames.length; ++i) { String dirName = dirNames[dirIndexes[i]]; StringBuilder sb = new StringBuilder(dirName); if (!dirName.endsWith("/")) sb.append('/'); sb.append(baseNames[i]); fileNames[i] = sb.toString(); } } int[] fileSizes = (int[]) header.get(HeaderTag.FILESIZES); String[] fileUserNames = (String[]) header.get(HeaderTag.FILEUSERNAME); String[] fileGroupNames = (String[]) header.get(HeaderTag.FILEGROUPNAME); int[] fileMTimes = (int[]) header.get(HeaderTag.FILEMTIMES); Bag bag = model.createBag(); rpmResource.addProperty(model.createProperty(RPM_NS, "files"), bag); for (int i = 0; i < fileNames.length; ++i) { Resource file = model.createResource(); file.addProperty(RDF.type, model.createResource(RPM_NS + "File")); file.addProperty(model.createProperty(RPM_NS, "name"), fileNames[i]); file.addLiteral(model.createProperty(RPM_NS, "size"), fileSizes[i]); file.addProperty(model.createProperty(RPM_NS, "username"), fileUserNames[i]); file.addProperty(model.createProperty(RPM_NS, "groupname"), fileGroupNames[i]); file.addProperty(model.createProperty(RPM_NS, "lastmodified"), model.createTypedLiteral(toDateTime(fileMTimes[i]).toString(), XSD.dateTime.getURI())); bag.add(file); } } private void processChangeLog(Map header) { if (header.containsKey(HeaderTag.CHANGELOGNAME) && header.containsKey(HeaderTag.CHANGELOGTEXT) && header.containsKey(HeaderTag.CHANGELOGTIME)) { String[] changeLogName = (String[]) header.get(HeaderTag.CHANGELOGNAME); String[] changeLogText = (String[]) header.get(HeaderTag.CHANGELOGTEXT); int[] changeLogTime = (int[]) header.get(HeaderTag.CHANGELOGTIME); Seq seq = model.createSeq(); rpmResource.addProperty(model.createProperty(RPM_NS, "changelog"), seq); for (int i = 0; i < changeLogName.length; ++i) { Resource entry = model.createResource(); entry.addProperty(RDF.type, model.createResource(RPM_NS + "ChangeLogEntry")); Matcher matcher = pattern.matcher(changeLogName[i]); if (matcher.matches()) { String name = matcher.group(1).trim(); String mail = matcher.group(2); Resource creator = model.createResource(); creator.addProperty(RDF.type, model.createResource(FOAF_NS + "Person")); creator.addProperty(model.createProperty(FOAF_NS, "name"), name); creator.addProperty(model.createProperty(FOAF_NS, "mbox"), model.createResource("mailto:" + mail)); entry.addProperty(DC.creator, creator); } else entry.addProperty(DC.creator, changeLogName[i]); entry.addProperty(DCTerms.created, model.createTypedLiteral(toDateTime(changeLogTime[i]).toString(), XSD.dateTime.getURI())); entry.addProperty(RDFS.comment, changeLogText[i]); seq.add(entry); } } } private void process(Map map, EnumSet tags) { Iterator iterator = tags.iterator(); while (iterator.hasNext()) { Tag tag = (Tag) iterator.next(); if (!map.containsKey(tag)) continue; RDFNode value = null; switch (tag.getType()) { case CHAR: { // We can simply omit this type because it is not used currently (none of the documented siganature tags or header tags uses this type) break; } case INT8: { byte[] byteArray = (byte[]) map.get(tag); if (byteArray.length > 1) { Seq seq = model.createSeq(); for (int i = 0; i < byteArray.length; ++i) { seq.add(model.createTypedLiteral(String.valueOf(byteArray[i]), XSD.xbyte.getURI())); } value = seq; } else value = model.createTypedLiteral(String.valueOf(byteArray[0]), XSD.xbyte.getURI()); break; } case INT16: { short[] shortArray = (short[]) map.get(tag); if (shortArray.length > 1) { Seq seq = model.createSeq(); for (int i = 0; i < shortArray.length; ++i) { seq.add(model.createTypedLiteral(String.valueOf(shortArray[i]), XSD.xshort.getURI())); } value = seq; } else value = model.createTypedLiteral(String.valueOf(shortArray[0]), XSD.xshort.getURI()); break; } case INT32: { int[] intArray = (int[]) map.get(tag); if (intArray.length > 1) { Seq seq = model.createSeq(); for (int i = 0; i < intArray.length; ++i) { seq.add(model.createTypedLiteral(intArray[i])); } value = seq; } else value = model.createTypedLiteral(intArray[0]); break; } case INT64: { // We can simply omit this type because it is not used (not supported) break; } case STRING: { value = model.createLiteral((String) map.get(tag)); break; } case BIN: { value = model.createTypedLiteral(new String(Base64.encodeBase64((byte[]) map.get(tag))), XSD.base64Binary.getURI()); break; } case STRING_ARRAY: { // serialize a string array as a Seq container Seq seq = model.createSeq(); String[] array = (String[]) map.get(tag); for (int i = 0; i < array.length; ++i) { seq.add(model.createLiteral(array[i])); } value = seq; break; } case I18NSTRING: { String[] array = (String[]) map.get(tag); if (array.length == 1) { value = model.createLiteral(array[0]); } else { // serialize a string array as an Alt container Alt alt = model.createAlt(); for (int i = 0; i < array.length; ++i) { alt.add(model.createLiteral(array[i])); } value = alt; } break; } } if (value != null) rpmResource.addProperty(model.createProperty(RPM_NS, tag.toXML()), value); } } private static interface DependencyFlags { public static final int LESS = 2; public static final int GREATER = 4; public static final int EQUAL = 8; } private static String getVersionPropertyName(int flags) { if ((flags & DependencyFlags.LESS) != 0) { return "minVersion" + ((flags & DependencyFlags.EQUAL) != 0 ? "Inclusive" : "Exclusive"); } else if ((flags & DependencyFlags.GREATER) != 0) { return "maxVersion" + ((flags & DependencyFlags.EQUAL) != 0 ? "Inclusive" : "Exclusive"); } if ((flags & DependencyFlags.EQUAL) != 0) return "version"; return null; } /** * Converts a POSIX time value to a W3C XML Schema <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">dateTime</a> value. * * @param seconds * @return */ private static XMLGregorianCalendar toDateTime(int seconds) { GregorianCalendar cal = new GregorianCalendar(); cal.setTimeInMillis(seconds * 1000L); try { return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal); } catch (DatatypeConfigurationException e) { return null; } } }