Skip to content

Conversation

@Sandared
Copy link

@Sandared Sandared commented Aug 2, 2018

I've added the bnd-maven-plugin to generate the necessary Manifest content, like

  • Bundle-Version
  • Bundle-Symbolic-Name
  • Require / Provide-Capability
  • WebJars-Resource

WebJars-Resource can be used in an OSGi environment to find WebJar bundles with a BundleTracker and register their resources at a HttpService.

Require-Capability is redeclaring the dependencies that are also used by maven, but in a format that the OSGi resolver can use to automatically resolve those dependencies.

The Bundle-Version has to be set manually if the ${project.version} is not OSGi compatible, e.g. a version like this: 1.2.3-2-SNAPSHOT. Bnd would ignore the "-2-" part and create the version like this: 1.2.3.SNAPSHOT, where probably something like 1.2.3.2-SNAPSHOT would be preferred. Therefore I had to create a new property bnd.bundle.version that is set to 1.2.3.2-SNAPSHOT to achieve this.

</developers>

<properties>
<bnd.bundle.version>3.3.1.2-SNAPSHOT</bnd.bundle.version>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to make bumping these easy by creating the unsnapshot plugin so I wonder if we can create a similar plugin that OSGI-ifies the version rather than having to edit it in multiple places.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've attached a piece of code that takes a maven version and tries to transform it into an OSGi version. In the worst case this will always return a version in the form 0.0.0.timestamp if the given maven version is completly malformed.

I have no experience with creating Maven plugins, so maybe you could just take this code an turn it into one?

public class OSGiVersion {
	
	public static void main(String[] args) {
		OSGiVersion osgiVersion = new OSGiVersion();
		
		String s1 = "1.2.3.4-_asdfasdf&/"; // malformed qualifier
		String s2 = ".asdf..33öjkhadsf"; // malformed segments and malformed qualifier
		String s3 = "1.asdf.3.asd.asdf.sdf"; // malformed segment and malformed qualifier
		String s4 = "1.2.3-beta1-2"; // everything ok
		String s5 = ""; // malformed version
		String s6 = "1.2-test"; // everything ok
		String s7 = "1.2-SNAPSHOT"; // everything ok
		
		System.out.println(osgiVersion.calculateVersion(s1));
		System.out.println(osgiVersion.calculateVersion(s2));
		System.out.println(osgiVersion.calculateVersion(s3));
		System.out.println(osgiVersion.calculateVersion(s4));
		System.out.println(osgiVersion.calculateVersion(s5));
		System.out.println(osgiVersion.calculateVersion(s6));
		System.out.println(osgiVersion.calculateVersion(s7));
	}

	/**
	 * @param mvnVersion
	 * @return a version that is compliant tothe description of OSGi versions by https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#i2655136
	 */
	public String calculateVersion(String mvnVersion) {
		
		// default OSGi version
		String[] bndVersionSegments = {"0", "0", "0", Long.toString(System.currentTimeMillis())};
		
		if(mvnVersion == null || mvnVersion.length() == 0) {
			// malformed version -> error message?
			System.err.println("Malformed version");
			return toVersionString(bndVersionSegments);
		}
		
		// remove all whitespaces
		mvnVersion = mvnVersion.replaceAll("\\s+", "");
		
		// get all segments, but at most 4 
		String[] mvnVersionSegments = mvnVersion.split("\\.", 4);
		
		for (int i = 0; i < mvnVersionSegments.length; i++) {
			String mvnSegment = mvnVersionSegments[i];
			String[] numberAndRest = getNumberAndRest(mvnSegment);
			
			switch (numberAndRest.length) {
			case 0:
				// no leading number found in this segment
				if(i == 3) {
					// it's ok, because it is the qualifier, which doesn't need to start with a number
					bndVersionSegments[3] = formatQualifier(mvnSegment);
				} else {
					// malformed segment -> error message?
					System.err.println("Malformed segment");
				}
				break;
			case 1:
				// it's a number. This is always acceptable
				bndVersionSegments[i] = numberAndRest[0];
				break;
			case 2:
				// it's a number with something else as rest.
				if(i == 3) {
					// it's ok because it is the qualifier
					bndVersionSegments[3] = formatQualifier(mvnSegment);
				} else{
					if(i == mvnVersionSegments.length - 1) {
						// it's ok because it is the last segment of the maven version. The rest is used as qualifier
						bndVersionSegments[i] = numberAndRest[0];
						bndVersionSegments[3] = formatQualifier(numberAndRest[1]);
					}
					else {
						// malformed segment -> error message?
						System.err.println("Malformed segment");
					}
				}
				break;
			default:
				// malformed return -> error message?
				System.err.println("Malformed return value of getNumberAndRest()");
				break;
			}
		}
		
		return toVersionString(bndVersionSegments);
	}
	
	
	/**
	 * 
	 * @param segment a String in the form of a leading number part and anything else as rest, e.g. 123 or 123asdf.
	 * @return a String array 'result' with length 0 if segment has no leading number, 1 if segment is a number (result[0] == segment), 2 if segment has a leading number and anything else as rest (result[0] == number, result[1] == rest)
	 */
	private String[] getNumberAndRest(String segment) {
		String pattern = "(\\d+)(.*)";
		if(segment.matches(pattern)) {
			String number = segment.replaceAll(pattern, "$1");
			String rest = segment.replaceAll(pattern, "$2");
			if(rest.length() == 0) {
				return new String[] {number};
			}
			return new String[]{number, rest};
		} else {
			return new String[0];
		}
	}
	
	
	/**
	 * @param qualifier an arbitrary String
	 * @return a String that only contains a-z, A-z, 0-9, -, _
	 */
	private String formatQualifier(String qualifier) {
		String wellFormedQualifier = qualifier.replaceAll("[^\\w_\\-]", "");
		if(wellFormedQualifier.length() != qualifier.length()) {
			// warning?
			System.err.println("Malformed qualifier");
		}
		return wellFormedQualifier;
	}
	
	/**
	 * @return the values of the array with dots in between as one String
	 */
	private String toVersionString(String[] segments) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < segments.length; i++) {
			String segment = segments[i];
			sb.append(segment);
			if(i != segments.length - 1) {
				sb.append(".");
			}
		}
		return sb.toString();
	}
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jamesward is there anything else you need for this plugin?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a repo for the plugin:
https://github.com/jamesward/osgi-version-maven-plugin

But the output isn't quite what I'd expect. For example:
https://github.com/jamesward/osgi-version-maven-plugin/blob/master/src/test/java/com/jamesward/osgiversion/UnsnapshotMojoTest.java#L32

The output of that one is 1.2.3.-beta1-.2 (the dashes are preserved. Anyhow, let's collaborate over on that repo and get it fixed up and released.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "-beta1-.2" part is regarded as the qualifier part of the OSGi version, which may contain dashes, but if those are not important, then I can alter the code to remove them. In OSGi they have no effect on the resolver, I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd look better without the dashes in the qualifier, at least without leading and trailing dashes. Want to send a PR?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sent you a PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants