/* * Copyright 2007 Alin Dreghiciu. * Copyright 2007 Peter Kriens. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * * See the License for the specific language governing permissions and * limitations under the License. */ package org.ops4j.pax.url.wrap.internal; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.ops4j.net.URLUtils; import org.ops4j.pax.swissbox.bnd.BndUtils; import org.ops4j.pax.swissbox.bnd.OverwriteMode; /** * Parser for wrap: protocol. * * @author Alin Dreghiciu * @see Connection * @since September 09, 2007 */ public class Parser { /** * Syntax for the url; to be shown on exception messages. */ private static final String SYNTAX = "wrap:wrapped-jar-uri[,wrapping-instr-uri][$wrapping-instructions]"; /** * Separator between wrapped jar url and instructions. */ private static final String INSTRUCTIONS_SEPARATOR = "$"; /** * Separator between wrapped jar url and instructions file url. */ private static final String INSTRUCTIONS_FILE_SEPARATOR = ","; /** * Regexp pattern for matching jar, wrapping file and instructions. */ private static final Pattern SYNTAX_JAR_BND_INSTR = Pattern.compile( "(.+?)" + INSTRUCTIONS_FILE_SEPARATOR + "(.+?)\\" + INSTRUCTIONS_SEPARATOR + "(.+?)" ); /** * Regexp pattern for matching jar and instructions. */ private static final Pattern SYNTAX_JAR_INSTR = Pattern.compile( "(.+?)\\" + INSTRUCTIONS_SEPARATOR + "(.+?)" ); /** * Regexp pattern for matching jar and wrapping file. */ private static final Pattern SYNTAX_JAR_BND = Pattern.compile( "(.+?)" + INSTRUCTIONS_FILE_SEPARATOR + "(.+?)" ); /** * Wrapped jar URL. */ private final URL m_wrappedJarURL; /** * Wrapping instructions URL. */ private final Properties m_wrappingProperties; /** * Manifest overwrite mode. */ private final OverwriteMode m_overwriteMode; /** * Creates a new protocol parser. * * @param path the path part of the url (without starting wrap:) * * @throws MalformedURLException if provided path does not comply to expected syntax or has malformed urls */ public Parser( final String path ) throws MalformedURLException { if( path == null || path.trim().length() == 0 ) { throw new MalformedURLException( "Path cannot be null or empty. Syntax " + SYNTAX ); } if( path.startsWith( INSTRUCTIONS_SEPARATOR ) || path.endsWith( INSTRUCTIONS_SEPARATOR ) ) { throw new MalformedURLException( "Path cannot start or end with " + INSTRUCTIONS_SEPARATOR + ". Syntax " + SYNTAX ); } m_wrappingProperties = new Properties(); Matcher matcher = SYNTAX_JAR_BND_INSTR.matcher( path ); if( matcher.matches() ) { // we have all the parts m_wrappedJarURL = new URL( matcher.group( 1 ) ); parseInstructionsFile( new URL( matcher.group( 2 ) ) ); m_wrappingProperties.putAll( BndUtils.parseInstructions( matcher.group( 3 ) ) ); } else if( ( matcher = SYNTAX_JAR_INSTR.matcher( path ) ).matches() ) { // we have a wrapped jar and instructions m_wrappedJarURL = new URL( matcher.group( 1 ) ); m_wrappingProperties.putAll( BndUtils.parseInstructions( matcher.group( 2 ) ) ); } else if( ( matcher = SYNTAX_JAR_BND.matcher( path ) ).matches() ) { // we have a wrapped jar and a wrapping instructions file m_wrappedJarURL = new URL( matcher.group( 1 ) ); parseInstructionsFile( new URL( matcher.group( 2 ) ) ); } else { //we have only a wrapped jar m_wrappedJarURL = new URL( path ); } OverwriteMode overwriteMode; try { overwriteMode = OverwriteMode.valueOf( m_wrappingProperties.getProperty( "overwrite", OverwriteMode.KEEP.name() ).toUpperCase() ); } catch( Exception e ) { overwriteMode = OverwriteMode.KEEP; } m_overwriteMode = overwriteMode; } /** * Loads the properties out of an url. * * @param bndFileURL url of the file containing the instructions * * @throws MalformedURLException if the file could not be read */ private void parseInstructionsFile( final URL bndFileURL ) throws MalformedURLException { // TODO use the certificate check property from the handler instead of true bellow try { InputStream is = null; try { is = URLUtils.prepareInputStream( bndFileURL, true ); m_wrappingProperties.load( is ); } finally { if( is != null ) { is.close(); } } } catch( IOException e ) { throwAsMalformedURLException( "Could not retrieve the instructions from [" + bndFileURL + "]", e ); } } /** * Returns the wrapped URL if present, null otherwise * * @return wrapped jar URL */ public URL getWrappedJarURL() { return m_wrappedJarURL; } /** * Returns the wrapping instructions as Properties. * * @return wrapping instructions as Properties */ public Properties getWrappingProperties() { return m_wrappingProperties; } /** * Returns the overwrite mode. * * @return overwrite mode */ public OverwriteMode getOverwriteMode() { return m_overwriteMode; } /** * Creates an MalformedURLException with a message and a cause. * * @param message exception message * @param cause exception cause * * @throws MalformedURLException the created MalformedURLException */ private static void throwAsMalformedURLException( final String message, final Exception cause ) throws MalformedURLException { final MalformedURLException exception = new MalformedURLException( message ); exception.initCause( cause ); throw exception; } }