blob: b0905216a004bfa1acda795c1cbed6b75b194b72 [file] [log] [blame]
Richard S. Hall85bafab2009-07-13 13:25:46 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package org.cauldron.bld.obr;
21
22import java.io.File;
23import java.net.URI;
24import java.net.URISyntaxException;
25import java.net.URL;
26import java.util.ArrayList;
27import java.util.Arrays;
28import java.util.HashSet;
29import java.util.LinkedList;
30import java.util.List;
31
32import org.cauldron.sigil.model.ModelElementFactory;
33import org.cauldron.sigil.model.common.LDAPExpr;
34import org.cauldron.sigil.model.common.LDAPParseException;
35import org.cauldron.sigil.model.common.LDAPParser;
36import org.cauldron.sigil.model.common.SimpleTerm;
37import org.cauldron.sigil.model.common.VersionRange;
38import org.cauldron.sigil.model.eclipse.ISigilBundle;
39import org.cauldron.sigil.model.osgi.IBundleModelElement;
40import org.cauldron.sigil.model.osgi.IPackageExport;
41import org.cauldron.sigil.model.osgi.IPackageImport;
42import org.cauldron.sigil.model.osgi.IRequiredBundle;
43import org.eclipse.core.runtime.IPath;
44import org.eclipse.core.runtime.Path;
45import org.osgi.framework.Version;
46import org.xml.sax.Attributes;
47import org.xml.sax.Locator;
48import org.xml.sax.SAXException;
49import org.xml.sax.SAXParseException;
50import org.xml.sax.helpers.DefaultHandler;
51
52final class OBRHandler extends DefaultHandler {
53 private static final String PACKAGE = "package";
54 private static final String URI = "uri";
55 private static final String PRESENTATION_NAME = "presentationname";
56 private static final String VERSION = "version";
57 private static final String SYMBOLIC_NAME = "symbolicname";
58 private final File cacheDir;
59 private final URL obrURL;
60 private final OBRListener listener;
61
62 private HashSet<String> sanity = new HashSet<String>();
63 private Locator locator;
64 private ISigilBundle bundle;
65 private IPackageExport export;
66
67 public OBRHandler(URL obrURL, File bundleCache, OBRListener listener) {
68 this.obrURL = obrURL;
69 this.cacheDir = bundleCache;
70 this.listener = listener;
71 }
72
73 public void setDocumentLocator (Locator locator) {
74 this.locator = locator;
75 }
76
77 public void startElement (String uri, String localName,
78 String qName, Attributes attributes) throws SAXException {
79 if ( "resource".equals( qName ) ) {
80 startResource(attributes);
81 }
82 else if ( "capability".equals( qName ) ) {
83 startCapability(attributes);
84 }
85 else if( "require".equals( qName ) ) {
86 startRequire(attributes);
87 }
88 else if ( "p".equals( qName ) ) {
89 startProperty(attributes);
90 }
91 }
92
93 public void endElement (String uri, String localName, String qName)
94 throws SAXException {
95 if ( "resource".equals( qName ) ) {
96 endResource();
97 }
98 else if ( "capability".equals( qName ) ) {
99 endCapability();
100 }
101 else if( "require".equals( qName ) ) {
102 endRequire();
103 }
104 else if ( "p".equals( qName ) ) {
105 endProperty();
106 }
107 }
108
109 private void startResource(Attributes attributes) throws SAXException {
110 try {
111 String uri = attributes.getValue("", URI);
112 if ( uri.endsWith( ".jar" ) ) {
113 if ( !sanity.add(uri) ) {
114 throw new RuntimeException(uri);
115 }
116 ISigilBundle b = ModelElementFactory.getInstance().newModelElement(ISigilBundle.class);
117 IBundleModelElement info = ModelElementFactory.getInstance().newModelElement(IBundleModelElement.class);
118 info.setSymbolicName(attributes.getValue("", SYMBOLIC_NAME));
119 info.setVersion(new Version(attributes.getValue("", VERSION)));
120 info.setName(attributes.getValue("", PRESENTATION_NAME));
121 URI l = makeAbsolute(uri);
122 info.setUpdateLocation(l);
123 b.setLocation(cachePath(info));
124 b.setBundleInfo(info);
125 bundle = b;
126 }
127 }
128 catch (Exception e) {
129 throw new SAXParseException("Failed to build bundle info", locator, e);
130 }
131 }
132
133 private URI makeAbsolute(String uri) throws URISyntaxException {
134 URI l = new URI(uri);
135 if ( !l.isAbsolute() ) {
136 String base = obrURL.toExternalForm();
137 int i = base.lastIndexOf("/");
138 if ( i != -1 ) {
139 base = base.substring(0, i);
140 l = new URI( base + (uri.startsWith("/") ? "" : "/") + uri );
141 }
142 }
143 return l;
144 }
145
146 private IPath cachePath(IBundleModelElement info) {
147 return new Path(cacheDir.getAbsolutePath()).append( info.getSymbolicName() + "_" + info.getVersion() + ".jar" );
148 }
149
150 private void startCapability(Attributes attributes) {
151 if ( bundle != null ) {
152 if ( PACKAGE.equals( attributes.getValue("", "name") ) ) {
153 export = ModelElementFactory.getInstance().newModelElement(IPackageExport.class);
154 }
155 }
156 }
157
158 private void startRequire(Attributes attributes) throws SAXParseException {
159 if ( bundle != null ) {
160 String name = attributes.getValue("name");
161 if ( PACKAGE.equals( name ) ) {
162 IPackageImport pi = ModelElementFactory.getInstance().newModelElement(IPackageImport.class);
163 try {
164 LDAPExpr expr = LDAPParser.parseExpression(attributes.getValue("filter") );
165 pi.setPackageName(decodePackage(expr, locator));
166 pi.setVersions(decodeVersions(expr, locator));
167 pi.setOptional(Boolean.valueOf(attributes.getValue("optional")));
168 bundle.getBundleInfo().addImport(pi);
169 } catch (LDAPParseException e) {
170 throw new SAXParseException("Failed to parse filter", locator, e);
171 }
172 }
173 else if ( "bundle".equals( name ) ) {
174 IRequiredBundle b = ModelElementFactory.getInstance().newModelElement(IRequiredBundle.class);
175 try {
176 LDAPExpr expr = LDAPParser.parseExpression(attributes.getValue("filter") );
177 b.setSymbolicName(decodeSymbolicName(expr, locator));
178 b.setVersions(decodeVersions(expr, locator));
179 b.setOptional(Boolean.valueOf(attributes.getValue("optional")));
180 bundle.getBundleInfo().addRequiredBundle(b);
181 } catch (Exception e) {
182 System.err.println( "Failed to parse filter in bundle " + bundle.getBundleInfo().getSymbolicName() );
183 throw new SAXParseException("Failed to parse filter in bundle " + bundle.getBundleInfo().getSymbolicName(), locator, e);
184 }
185 }
186 //else if ( "ee".equals( name ) ) {
187 // TODO ignore for now...
188 //}
189 //else if ( "service".equals( name ) ) {
190 // TODO ignore for now...
191 //}
192 //else {
193 // for ( int i = 0; i < attributes.getLength(); i++ ) {
194 // System.out.println( "Found requirement " + attributes.getValue(i) );
195 // }
196 //}
197 }
198 }
199
200 private static VersionRange decodeVersions(LDAPExpr expr, Locator locator) throws SAXParseException {
201 try {
202 return VersionRangeHelper.decodeVersions(expr);
203 }
204 catch (NumberFormatException e) {
205 throw new SAXParseException(e.getMessage(), locator);
206 }
207 }
208
209 private void startProperty(Attributes attributes) {
210 if ( export != null ) {
211 String name = attributes.getValue("", "n");
212 String value = attributes.getValue("", "v");
213 if ( PACKAGE.equals( name ) ) {
214 export.setPackageName(value);
215 }
216 else if ( "uses".equals( name ) ) {
217 String[] split = value.split(",");
218 export.setUses( Arrays.asList(split) );
219 }
220 else if ( "version".equals( name ) ) {
221 export.setVersion( new Version(value) );
222 }
223 }
224 }
225
226 private void endResource() {
227 if ( bundle != null ) {
228 listener.handleBundle(bundle);
229 bundle = null;
230 }
231 }
232
233 private void endCapability() {
234 if ( bundle != null ) {
235 if ( export != null ) {
236 bundle.getBundleInfo().addExport(export);
237 export = null;
238 }
239 }
240 }
241
242 private void endRequire() {
243 // TODO Auto-generated method stub
244
245 }
246
247 private void endProperty() {
248 // TODO Auto-generated method stub
249
250 }
251
252 private static String decodePackage(LDAPExpr expr, Locator locator) throws SAXParseException {
253 ArrayList<SimpleTerm> terms = new ArrayList<SimpleTerm>(1);
254
255 findTerms("package", expr, terms);
256
257 if ( terms.isEmpty() ) {
258 throw new SAXParseException("Missing name filter in " + expr, locator);
259 }
260
261 return terms.get(0).getRval();
262 }
263
264 private static String decodeSymbolicName(LDAPExpr expr, Locator locator) throws SAXParseException {
265 ArrayList<SimpleTerm> terms = new ArrayList<SimpleTerm>(1);
266
267 findTerms("symbolicname", expr, terms);
268
269 if ( terms.isEmpty() ) {
270 throw new SAXParseException("Missing name filter in " + expr, locator);
271 }
272
273 return terms.get(0).getRval();
274 }
275
276 private static void findTerms(String string, LDAPExpr expr, List<SimpleTerm> terms) throws SAXParseException {
277 if ( expr instanceof SimpleTerm ) {
278 SimpleTerm term = (SimpleTerm) expr;
279 if ( term.getName().equals(string) ) {
280 terms.add(term);
281 }
282 }
283 else {
284 for ( LDAPExpr c : expr.getChildren() ) {
285 findTerms(string, c, terms);
286 }
287 }
288 }
289}