/* * Copyright 2009 Alin Dreghiciu. * * 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.assembly.internal; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Collection; import java.util.HashSet; import java.util.regex.Pattern; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.ops4j.io.ListerUtils; /** * Parser for "assemblyref:" protocol where the url referes to an assembly descriptor file. * Descriptor file should be a json file. * * @author Alin Dreghiciu * @since 1.1.0, August 31, 2009 */ class AssemblyDescriptorParser implements Parser { /** * Parsed manifest path. */ private String m_manifest; /** * Parsed array of sources. */ private Source[] m_sources; /** * Parsed merge policy. */ private MergePolicy m_mergePolicy; /** * Constructor. * * @param url the path part of the url (without starting assemblyref:) * * @throws IOException - IIf a problem encountered while parsing descriptor file */ AssemblyDescriptorParser( final String url ) throws IOException { if( url == null ) { throw new MalformedURLException( "Url cannot be null. Syntax " + SYNTAX ); } if( "".equals( url.trim() ) || "/".equals( url.trim() ) ) { throw new MalformedURLException( "Url cannot be empty. Syntax " + SYNTAX ); } m_sources = new Source[0]; m_mergePolicy = MergePolicy.FIRST; parseDescriptor( new URL( url ) ); } /** * {@inheritDoc} */ public String manifest() { return m_manifest; } /** * {@inheritDoc} */ public Source[] sources() { return m_sources; } /** * Returns merge policy based on descriptor. If not specified returns a first wins merge policy. * * {@inheritDoc} */ public MergePolicy mergePolicy() { return m_mergePolicy; } /** * Reads descriptor file. * * @param url descriptor file url * * @throws IOException - If a problem encountered while parsing descriptor file */ private void parseDescriptor( final URL url ) throws IOException { final JsonFactory jFactory = new JsonFactory(); jFactory.enable( JsonParser.Feature.ALLOW_COMMENTS ); final JsonParser jp = jFactory.createJsonParser( url ); if( jp.nextToken() != JsonToken.START_OBJECT ) { throw new IOException( String.format( "Descriptor [%s] not in JSON format", url.toExternalForm() ) ); } final Collection<Source> sources = new HashSet<Source>(); try { while( jp.nextToken() != JsonToken.END_OBJECT ) { final String currentName = jp.getCurrentName(); jp.nextToken(); if( "manifest".equals( currentName ) ) { m_manifest = jp.getText(); } else if( "assembly".equals( currentName ) ) { sources.addAll( parseAssembly( jp ) ); } else if( "mergePolicy".equals( currentName ) ) { m_mergePolicy = "last".equalsIgnoreCase( jp.getText() ) ? MergePolicy.LAST : MergePolicy.FIRST; } } } finally { jp.close(); } m_sources = sources.toArray( new Source[sources.size()] ); } /** * Parses "directories" section. * * @param jp json parser. * * @return parsed sources * * @throws IOException - If a problem encountered while parsing descriptor file */ private Collection<Source> parseAssembly( final JsonParser jp ) throws IOException { final Collection<Source> sources = new HashSet<Source>(); while( jp.nextToken() != JsonToken.END_OBJECT ) { final String currentName = jp.getCurrentName(); jp.nextToken(); if( "directory".equals( currentName ) || "jar".equals( currentName ) || "zip".equals( currentName) ) { final Source source = parseDirectory( jp ); sources.add( source ); } } return sources; } /** * Parses "directory" section. * * @param jp json parser. * * @return parsed source * * @throws IOException - If a problem encountered while parsing descriptor file */ private Source parseDirectory( final JsonParser jp ) throws IOException { String path = null; final Collection<Pattern> includes = new HashSet<Pattern>(); final Collection<Pattern> excludes = new HashSet<Pattern>(); while( jp.nextToken() != JsonToken.END_OBJECT ) { final String currentName = jp.getCurrentName(); jp.nextToken(); if( "path".equals( currentName ) ) { path = jp.getText(); } else if( "include".equals( currentName ) ) { includes.add( ListerUtils.parseFilter( jp.getText() ) ); } else if( "exclude".equals( currentName ) ) { excludes.add( ListerUtils.parseFilter( jp.getText() ) ); } } if( path == null ) { throw new IOException( "Invalid descriptor file" ); } return new ImmutableSource( path, includes.toArray( new Pattern[includes.size()] ), excludes.toArray( new Pattern[excludes.size()] ) ); } }