package org.ovirt.engine.core.compat; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlType; /** * Class used to extract and represent a version of RPM. It support several patterns: * <li> {@literal <name>-<version>-<release>.<architecture>.rpm} - version part is not allowed to contain "-". * Supported by {@link RpmVersion#RpmVersion(String)} * <li> {@literal <prefix+name>[ -].*<[0-9].*\\.}{1,3}[0-9] {@literal><any text>} e.g: * <i>rhev-agent-2.3.7-1.el6</i> or <i>RHEV-Agent 2.3.395</i>. Supported by {@link RpmVersion#RpmVersion(String, String, boolean)} */ @XmlAccessorType(XmlAccessType.NONE) @XmlType(name = "RpmVersion") public class RpmVersion extends Version { private static final long serialVersionUID = 5938069430310131270L; private static final String RPM_REGEX = "([^ ]+)\\-([0-9][^ \\-]*\\-[0-9\\.]+)\\.(.*)"; private static Pattern rpmCompiled = Pattern.compile(RPM_REGEX); private String rpmName; public RpmVersion() { super(); } /** * {@literal Supports RPM format by spec: <name>-<version>-<release>.<architecture>.rpm} * @param rpmName * the RPM name */ public RpmVersion(String rpmName) { this.rpmName = rpmName; if (rpmName == null || rpmName.isEmpty()) { setValue(rpmName); } else { setValue(extractRpmVersion(rpmName)); } } /** * Support RPM version extraction where a given prefix is omitted from the RPM name. * @param rpmName * the full RPM name * @param namePrefix * a prefix which is part of the RPM name and should ignored (case insensitive) while extracting the * version * @param ignoreCaseSensitive * an indicator whether to ignore the case of the given prefix, if known ahead */ public RpmVersion(String rpmName, String namePrefix, boolean ignoreCaseSensitive) { this.rpmName = rpmName; if (rpmName == null || rpmName.isEmpty()) { setValue(rpmName); } else { if (namePrefix == null) { namePrefix = ""; } int start = -1; if (ignoreCaseSensitive) { start = rpmName.toLowerCase().indexOf(namePrefix.toLowerCase()); } else { start = rpmName.indexOf(namePrefix); } String rawVersion; if (start > -1) { rawVersion = rpmName.substring(start + namePrefix.length()); } else { rawVersion = rpmName; } setValue(extractRpmVersion(rawVersion.toCharArray())); } } @XmlElement(name = "RpmName") public String getRpmName() { return this.rpmName; } public void setRpmName(String rpmName) { // for wsdl purpose only } /** * Extracts the version out of a given array of characters by the following algorithm: * <li>Find first digit location after tool name (case ignored). * <li>Parse as many version parts elements as provided, up to 4. * <li>Set default value "0" for the missing parts. * @param version * the char material which contains the version * @return a string contains a version in format of w.x.y.z where w,x,y and z are int. */ private static String extractRpmVersion(char[] version) { int start = indexOfFirstDigit(version); int end = version.length; int dots = 3; for (int i = start; i < end; i++) { if (!Character.isDigit(version[i]) && version[i] != '.') { end = i; break; } else if (version[i] == '.') { if (dots == 0) { end = i; break; } dots--; } } StringBuilder sb = new StringBuilder(new String(version, start, end - start)); for (int i = 0; i < dots; i++) { sb.append(".0"); } return sb.toString(); } private String extractRpmVersion(String rpmName) { Matcher matchToolPattern = rpmCompiled.matcher(rpmName); String rawString = null; if (matchToolPattern.find() && matchToolPattern.groupCount() > 1) { rawString = matchToolPattern.group(2); return extractRpmVersion(rawString.toCharArray()); } return null; } private static int indexOfFirstDigit(char[] version) { int i = 0; for (; i < version.length; i++) { if (Character.isDigit(version[i])) { break; } } return i; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((rpmName == null) ? 0 : rpmName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; RpmVersion other = (RpmVersion) obj; if (rpmName == null) { if (other.rpmName != null) return false; } else if (!rpmName.equals(other.rpmName)) return false; return true; } }