package org.apache.maven.artifact.repository; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.StringTokenizer; 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.NodeList; import org.xml.sax.SAXException; public class MavenJPackageDepmap { private static class ArtifactDefinition { String groupId = null; String artifactId = null; String version = null; } /** * * @author Stanislav Ochotnicky * * This class is used to wrap around fragments that are mapping * artifacts to jar files in our _javadir. These used to be * processed in a macro after every package installation. Fragments * themselves are not proper xml files (they have no root element) * so we have to fix them by wrapping them in one root element. */ private static class WrapFragmentStream extends InputStream { String startTag = ""; String endTag = ""; byte fragmentContent[]; int position; WrapFragmentStream(String fragmentPath) throws IOException { FileInputStream fin = new FileInputStream(fragmentPath); int nBytes = fin.available(); byte tmpContent[] = new byte[nBytes]; fin.read(tmpContent); fin.close(); byte startBytes[] = startTag.getBytes(); byte endBytes[] = endTag.getBytes(); fragmentContent = new byte[nBytes + startBytes.length + endBytes.length]; System.arraycopy(startBytes, 0, fragmentContent, 0, startBytes.length); System.arraycopy(tmpContent, 0, fragmentContent, startBytes.length, tmpContent.length); System.arraycopy(endBytes, 0, fragmentContent, startBytes.length + tmpContent.length, endBytes.length); position = 0; } public int read() throws IOException { if (position < fragmentContent.length) { return fragmentContent[position++]; } else { return -1; } } } private static MavenJPackageDepmap instance; private static Hashtable jppArtifactMap; private static Hashtable> jppUnversionedArtifactMap; private MavenJPackageDepmap() { jppArtifactMap = new Hashtable(); jppUnversionedArtifactMap = new Hashtable>(); buildJppArtifactMap(); } public static MavenJPackageDepmap getInstance() { if (instance == null) { instance = new MavenJPackageDepmap(); } return instance; } /** * This function can be used to query exact version of an artifact. * * @param groupId * @param artifactId * @param version * @return Hashtable mapping for groupId, artifactId and version or null if * exact mapping not found */ public Hashtable getMappedInfo(String groupId, String artifactId, String version) { Hashtable jppDep; String idToCheck, jppCombination; idToCheck = groupId + "," + artifactId + "," + version; jppCombination = (String) jppArtifactMap.get(idToCheck); jppDep = null; if (jppCombination != null && jppCombination != "") { StringTokenizer st = new StringTokenizer(jppCombination, ","); jppDep = new Hashtable(); jppDep.put("group", st.nextToken()); jppDep.put("artifact", st.nextToken()); jppDep.put("version", st.nextToken()); } return jppDep; } /** * This function can be used to query for all possible artifact resolutions. * It works with multiple duplicate gid:aid mappings, but only one should * have unversioned files (default version) to work properly later * * @param groupId * @param artifactId * @param version * @return */ public ArrayList> getUnversionedMappedInfo( String groupId, String artifactId, String version) { Hashtable jppDep; String idToCheck; List maps; idToCheck = groupId + "," + artifactId; maps = jppUnversionedArtifactMap.get(idToCheck); ArrayList> ret = new ArrayList>(); if (maps != null) { for (String jppPart : maps) { jppDep = new Hashtable(); StringTokenizer st = new StringTokenizer(jppPart, ","); jppDep.put("group", st.nextToken()); jppDep.put("artifact", st.nextToken()); jppDep.put("version", st.nextToken()); // we add to index 0 to make it reversed order for compatibility // with older code ret.add(0, jppDep); } } return ret; } private static void buildJppArtifactMap() { processDepmapFile("/etc/maven/maven2-versionless-depmap.xml"); // process fragments in etc File fragmentDir = new File("/etc/maven/fragments"); String flist[] = fragmentDir.list(); if (flist != null) { java.util.Arrays.sort(flist); for (String fragFilename : flist) processDepmapFile("/etc/maven/fragments/" + fragFilename); } // process fragments is usr. Once packages are rebuilt, we can skip // fragments in /etc fragmentDir = new File("/usr/share/maven-fragments"); flist = fragmentDir.list(); if (flist != null) { java.util.Arrays.sort(flist); for (String fragFilename : flist) processDepmapFile("/usr/share/maven-fragments/" + fragFilename); } String customFileName = System.getProperty("maven.local.depmap.file", null); if (customFileName != null) { processDepmapFile(customFileName); } } private static void processDepmapFile(String fileName) { Document mapDocument; debug("Loading depmap file: " + fileName); try { DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance(); fact.setNamespaceAware(true); DocumentBuilder builder = fact.newDocumentBuilder(); // we can wrap even old depmaps, no harm done WrapFragmentStream wfs = new WrapFragmentStream(fileName); mapDocument = builder.parse(wfs); wfs.close(); } catch (FileNotFoundException fnfe) { System.err.println("ERROR: Unable to find map file: " + fileName); fnfe.printStackTrace(); return; } catch (IOException ioe) { System.err .println("ERROR: I/O exception occured when opening map file"); ioe.printStackTrace(); return; } catch (ParserConfigurationException pce) { System.err .println("ERROR: Parsing of depmap file failed - configuration"); pce.printStackTrace(); return; } catch (SAXException se) { System.err.println("ERROR: Parsing of depmap file failed"); se.printStackTrace(); return; } NodeList depNodes = (NodeList) mapDocument .getElementsByTagName("dependency"); for (int i = 0; i < depNodes.getLength(); i++) { Element depNode = (Element) depNodes.item(i); NodeList mavenNodeList = (NodeList) depNode .getElementsByTagName("maven"); if (mavenNodeList.getLength() != 1) { debug("Number of maven sub-elements is not 1. Bailing from depmap generation"); debug("Maven node: " + depNode.getTextContent()); return; } ArtifactDefinition mavenAD = getArtifactDefinition((Element) mavenNodeList .item(0)); ArtifactDefinition jppAD = null; NodeList jppNodeList = (NodeList) depNode .getElementsByTagName("jpp"); if (jppNodeList.getLength() == 1) { jppAD = getArtifactDefinition((Element) jppNodeList.item(0)); debug("*** Adding: " + mavenAD.groupId + "," + mavenAD.artifactId + " => " + jppAD.groupId + "," + jppAD.artifactId + "," + jppAD.version + " to map..."); jppArtifactMap.put(mavenAD.groupId + "," + mavenAD.artifactId + "," + mavenAD.version, jppAD.groupId + "," + jppAD.artifactId + "," + jppAD.version); ArrayList maps = jppUnversionedArtifactMap .get(mavenAD.groupId + "," + mavenAD.artifactId); if (maps == null) { maps = new ArrayList(); } maps.add(jppAD.groupId + "," + jppAD.artifactId + "," + jppAD.version); jppUnversionedArtifactMap.put(mavenAD.groupId + "," + mavenAD.artifactId, maps); } else { debug("Number of jpp sub-elements is not 1. Dropping dependency for " + mavenAD.groupId + ":" + mavenAD.artifactId); jppArtifactMap.put(mavenAD.groupId + "," + mavenAD.artifactId + "," + mavenAD.version, "JPP/maven,empty-dep," + mavenAD.version); ArrayList maps = new ArrayList(); maps.add("JPP/maven,empty-dep," + mavenAD.version); jppUnversionedArtifactMap.put(mavenAD.groupId + "," + mavenAD.artifactId, maps); } } } private static ArtifactDefinition getArtifactDefinition(Element element) { ArtifactDefinition ad = new ArtifactDefinition(); NodeList nodes = element.getElementsByTagName("groupId"); if (nodes.getLength() != 1) { debug("groupId definition not found in depmap"); return null; } ad.groupId = nodes.item(0).getTextContent(); nodes = element.getElementsByTagName("artifactId"); if (nodes.getLength() != 1) { debug("artifactId definition not found in depmap"); return null; } ad.artifactId = nodes.item(0).getTextContent(); nodes = element.getElementsByTagName("version"); if (nodes.getLength() != 1) { ad.version = "DUMMY_VER"; } else { ad.version = nodes.item(0).getTextContent(); } return ad; } public static void debug(String msg) { if (System.getProperty("maven.local.debug") != null) System.err.println(msg); } }