View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.springframework.roo.addon.surf.component;
20  
21  import java.io.File;
22  import java.io.InputStream;
23  import java.util.Hashtable;
24  import java.util.SortedSet;
25  import java.util.TreeSet;
26  import java.util.logging.Logger;
27  
28  import org.springframework.roo.addon.surf.Constants;
29  import org.springframework.roo.addon.surf.SurfOperations;
30  import org.springframework.roo.addon.surf.page.PageOperations;
31  import org.springframework.roo.addon.surf.region.RegionConfig;
32  import org.springframework.roo.addon.surf.template.TemplateOperations;
33  import org.springframework.roo.addon.surf.util.ComponentConfigUtils;
34  import org.springframework.roo.addon.surf.util.SurfUtils;
35  import org.springframework.roo.file.monitor.event.FileDetails;
36  import org.springframework.roo.metadata.MetadataService;
37  import org.springframework.roo.process.manager.FileManager;
38  import org.springframework.roo.process.manager.MutableFile;
39  import org.springframework.roo.project.Path;
40  import org.springframework.roo.project.PathResolver;
41  import org.springframework.roo.project.ProjectOperations;
42  import org.springframework.roo.support.lifecycle.ScopeDevelopment;
43  import org.springframework.roo.support.util.Assert;
44  import org.springframework.roo.support.util.TemplateUtils;
45  import org.springframework.roo.support.util.XmlUtils;
46  import org.w3c.dom.Document;
47  import org.w3c.dom.Element;
48  
49  /**
50   * Provides Surf component related operations.
51   *
52   * @author Yong Qu
53   * @since 1.0
54   */
55  @ScopeDevelopment
56  public class ComponentOperations {
57  
58  	Logger logger = Logger.getLogger(ComponentOperations.class.getName());
59  
60  	private FileManager fileManager;
61  	private PathResolver pathResolver;
62  	private MetadataService metadataService;
63  	private ProjectOperations projectOperations;
64  
65  	private String surfComponentsRootPath;
66  
67  	private SurfOperations surfOperations;
68  
69  
70  	/**
71  	 * @param fileManager
72  	 * @param pathResolver
73  	 * @param metadataService
74  	 * @param projectOperations
75  	 */
76  	public ComponentOperations(FileManager fileManager, PathResolver pathResolver, MetadataService metadataService, ProjectOperations projectOperations) {
77  		Assert.notNull(fileManager, "File manager required");
78  		Assert.notNull(pathResolver, "Path resolver required");
79  		Assert.notNull(metadataService, "Metadata service required");
80  		Assert.notNull(projectOperations, "Project operations required");
81  
82  		this.fileManager = fileManager;
83  		this.pathResolver = pathResolver;
84  		this.metadataService = metadataService;
85  		this.projectOperations = projectOperations;
86  
87  		this.surfOperations = new SurfOperations(fileManager, pathResolver, metadataService, projectOperations);
88  		this.surfComponentsRootPath = pathResolver.getRoot(Path.SRC_MAIN_WEBAPP) + "/"+Constants.SURF_SITEDATA_COMPONENT_CP;
89  
90  	}
91  
92  	/**
93  	 * Checks if Surf component related operations are available.
94  	 * @return true if Surf component related operations are available.
95  	 */
96  	public boolean isSurfComponentOperationsAvailable() {
97  		return surfOperations.isManageSurfAvailable();
98  	}
99  
100 	/**
101 	 * Returns list of global scoped Surf components.
102 	 * @return List of global scoped Surf components.
103 	 */
104 	public SortedSet<String> listGlobalScopedSurfComponents() {
105 
106 		String antPath = (surfComponentsRootPath+"*.xml").replace("/", File.separator);
107 		SortedSet<FileDetails> entries = fileManager.findMatchingAntPath(antPath);
108 		SortedSet<String> componentList = new TreeSet<String>();
109 
110 		// Global-scope components.
111 		for (FileDetails fileIdentifier : entries) {
112 			Document componentDoc = SurfUtils.getSurfXMLDoc(fileManager, fileIdentifier);
113 			Element componentElem = ComponentConfigUtils.getComponentElem( componentDoc);
114 			if (componentElem != null )
115 				componentList.add("Scope:"+Constants.SURF_SCOPE_GLOBAL+" "+ComponentConfigUtils.componentToString(componentElem));
116 		}
117 
118 		return componentList;
119 	}	
120 
121 	/**
122 	 * List of page scoped Surf components.
123 	 * @param pageId Page id.
124 	 * @return List of page scoped Surf components.
125 	 */
126 	public SortedSet<String> listPageScopedSurfComponents(String pageId) {
127 
128 		SortedSet<String> componentList = new TreeSet<String>();
129 
130 		// Page-scope components.
131 		PageOperations pageOperations = new PageOperations(fileManager, pathResolver, metadataService, projectOperations);
132 		for (FileDetails page:pageOperations.getSurfPages().values()) {
133 
134 			Document pageDoc = SurfUtils.getSurfXMLDoc(fileManager, page);
135 			String componentPageId = XmlUtils.findFirstElementByName("id", (Element) pageDoc.getFirstChild()).getTextContent();
136 
137 			for (Element componentElem : ComponentConfigUtils.getComponentsElems(pageDoc)) {
138 				if ( pageId == null || pageId.equals("")) {
139 					componentList.add("Scope:"+Constants.SURF_SCOPE_PAGE+" Page Id:"+componentPageId+" "+ComponentConfigUtils.componentToString(componentElem));					
140 				} else if (pageId.equals(componentPageId) ) {
141 					componentList.add("Scope:"+Constants.SURF_SCOPE_PAGE+" Page Id:"+componentPageId+" "+ComponentConfigUtils.componentToString(componentElem));
142 				}
143 			}
144 		}		
145 
146 		return componentList;
147 	}	
148 
149 	/**
150 	 * Returns list of template scoped Surf component.
151 	 * @param templateId Template id.
152 	 * @return List of template scoped Surf component.
153 	 */
154 	public SortedSet<String> listTemplateScopedSurfComponents(String templateId) {
155 
156 		SortedSet<String> componentList = new TreeSet<String>();
157 
158 		// Page-scope components.
159 		TemplateOperations templateOperations = new TemplateOperations(fileManager, pathResolver, metadataService, projectOperations);
160 		for (FileDetails template:templateOperations.getSurfTemplateInstances().values()) {
161 
162 			Document templateDoc = SurfUtils.getSurfXMLDoc(fileManager, template);
163 			String componentTemplateId = XmlUtils.findFirstElementByName("id", (Element) templateDoc.getFirstChild()).getTextContent();
164 
165 			for (Element componentElem : ComponentConfigUtils.getComponentsElems(templateDoc)) {
166 				if ( templateId ==null || templateId.equals("")) {
167 					componentList.add("Scope:"+Constants.SURF_SCOPE_TEMPLATE+" Template Id:"+componentTemplateId+" "+ComponentConfigUtils.componentToString(componentElem));					
168 				} else if ( templateId.equals(componentTemplateId)) {
169 					componentList.add("Scope:"+Constants.SURF_SCOPE_TEMPLATE+" Template Id:"+componentTemplateId+" "+ComponentConfigUtils.componentToString(componentElem));
170 				}
171 			}
172 		}		
173 
174 		return componentList;
175 	}	
176 
177 	/**
178 	 * Returns all available components.
179 	 * @param scopeId Component scope.
180 	 * @param pageId Page id.
181 	 * @param templateId Template id.
182 	 * @return List of components.
183 	 */
184 	public SortedSet<String> listSurfComponents(String scopeId,String pageId,String templateId) {
185 
186 		SortedSet<String> componentList = new TreeSet<String>();
187 
188 		if (pageId != null && !pageId.equals("")){
189 			// Page-scope components.
190 			componentList.addAll(listPageScopedSurfComponents(pageId));			
191 		} else if (templateId != null && !templateId.equals("")) {
192 			// Template-scope components.
193 			componentList.addAll(listTemplateScopedSurfComponents(templateId));			
194 		} else if (scopeId != null && scopeId.equals(Constants.SURF_SCOPE_GLOBAL)) {
195 			// Global-scope components.
196 			componentList.addAll(listGlobalScopedSurfComponents());			
197 		} else if (scopeId != null && scopeId.equals(Constants.SURF_SCOPE_PAGE)) {
198 			// Page-scope components.
199 			componentList.addAll(listPageScopedSurfComponents(pageId));
200 		} else if (scopeId != null && scopeId.equals(Constants.SURF_SCOPE_TEMPLATE)) {
201 			// Template-scope components.
202 			componentList.addAll(listTemplateScopedSurfComponents(templateId));			
203 		} else {
204 			// Global-scope components.
205 			componentList.addAll(listGlobalScopedSurfComponents());
206 			// Page-scope components.
207 			componentList.addAll(listPageScopedSurfComponents(pageId));
208 			// Template-scope components.
209 			componentList.addAll(listTemplateScopedSurfComponents(templateId));
210 		}
211 		return componentList;
212 	}
213 	/**
214 	 * Returns list of all available component types.
215 	 * @return List of component types.
216 	 */
217 	public SortedSet<String> listSurfComponentTypes() {
218 
219 		String surfComponentsRootPath = pathResolver.getRoot(Path.SRC_MAIN_WEBAPP)+"/"+Constants.WEB_INF+"/";
220 		String antPath = surfComponentsRootPath+"**/*.desc.xml";
221 		antPath = antPath.replace("/", File.separator);
222 
223 		SortedSet<FileDetails> entries = fileManager.findMatchingAntPath(antPath);
224 		SortedSet<String> componentList = new TreeSet<String>();
225 
226 		for (FileDetails fileIdentifier : entries) {
227 			InputStream templateInstanceInputStream = fileManager.getInputStream(fileIdentifier.getCanonicalPath());
228 			Document pom;
229 			try {
230 				pom = XmlUtils.getDocumentBuilder().parse(templateInstanceInputStream);
231 			} catch (Exception ex) {
232 				throw new IllegalStateException(ex);
233 			}
234 			Element rootElement = (Element) pom.getFirstChild();
235 			//Element familyElement = XmlUtils.findFirstElementByName("family", rootElement);
236 
237 			//if ( familyElement != null ) {
238 			//if ( familyElement.getTextContent().equals("component") ) {
239 			Element urlElement = XmlUtils.findFirstElementByName("url", rootElement);
240 			if ( urlElement != null) {
241 				componentList.add(urlElement.getTextContent());
242 			}
243 			//}
244 			//}
245 
246 			try {
247 				templateInstanceInputStream.close();
248 			} catch (Exception ex) {
249 				throw new IllegalStateException(ex);
250 			}
251 
252 		}
253 
254 		return componentList;
255 	}
256 
257 	/**
258 	 * Checks if a Surf component exists or not.
259 	 * @param componentId Component id.
260 	 * @return True if it exists. False if it doesn't.
261 	 */
262 	public boolean isSurfComponentAvailable(String componentId) {
263 		SortedSet<String> componentList = listSurfComponents(null,null,null);
264 		return componentList.contains(componentId);
265 	}
266 
267 	/**
268 	 * Checks if the component type is available.
269 	 * @param componentPath Component path .
270 	 * @return True if it exists. False if it doesn't.
271 	 */
272 	public boolean isSurfComponentTypeAvailable(String componentPath) {
273 		SortedSet<String> componentList = listSurfComponentTypes();
274 		return componentList.contains(componentPath);
275 	}
276 
277 	/**
278 	 * Creates a new component.
279 	 * @param pageId Page id.
280 	 * @param templatePath Path of the template used for creating component.
281 	 * @param regionId Region id.
282 	 * @param componentType Component type.
283 	 * @param options Additional options.
284 	 */
285 	public void createComponent(String pageId, String regionId, String componentType, String options) {
286 		Assert.hasText(pageId, "Page name required");
287 		Assert.hasText(regionId, "Region id required");
288 		Assert.hasText(componentType, "Component url required");
289 
290 		PageOperations pageOperations = new PageOperations(fileManager, pathResolver, metadataService, projectOperations);
291 
292 		FileDetails pageXml = pageOperations.findSurfPageById(pageId);
293 		if ( pageXml == null) {
294 			logger.warning("Page "+pageId+" doesn't exist.");
295 			return;
296 		}
297 		String templatePath = pageOperations.getTemplatePath(pageId);
298 		if ( templatePath ==null || templatePath.equals("")) {
299 			logger.warning("Can't find template for page "+pageId);
300 			return;
301 		}
302 
303 		// Check if the template exists.
304 		TemplateOperations templateOperations = new TemplateOperations(fileManager, pathResolver, metadataService, projectOperations);
305 
306 		if ( templateOperations.findSurfTemplateByPath(templatePath) == null ) {
307 			logger.warning("Template "+templatePath+" doesn't exist");
308 			logger.warning("Available Templates:");
309 			logger.warning(""+templateOperations.listSurfTemplates());
310 			return;
311 		}
312 		// Check if the region exists.
313 		Hashtable<String,RegionConfig> regionList = templateOperations.listSurfTemplateRegions(templatePath);
314 		if ( ! regionList.containsKey(regionId) ) {
315 			logger.warning("Region "+regionId+" doesn't exist");
316 			logger.warning("Available Regions:");
317 			logger.warning(""+regionList.values());
318 			return;
319 		}
320 		// Check if the component type exists.
321 		/*
322 		SortedSet<String> componentTypes = listSurfComponentTypes();
323 		if ( ! componentTypes.contains(componentType) ) {
324 			logger.warning("Component Type "+componentType+" doesn't exist");
325 			logger.warning("Available Component Types:");
326 			logger.warning(""+componentTypes);
327 			return;
328 		}
329 		 */
330 		RegionConfig regionConfig = regionList.get(regionId);
331 
332 		String scope = regionConfig.getScope();
333 
334 		String componentInstanceName = "";
335 		String sourceId ="";
336 		InputStream componentInstanceInputStream;
337 
338 		if ( scope.equals("global") ) {
339 			componentInstanceName = "global."+regionId;
340 			sourceId ="global";
341 			logger.warning(componentInstanceName);
342 			//Find component template and fill up the xml file.
343 			String componentInstanceXmlFilename = Constants.SURF_SITEDATA_COMPONENT_CP+componentInstanceName+".xml";
344 			if (fileManager.exists(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename))) {
345 				//file exists, so nothing to do
346 				logger.warning("Component "+componentInstanceXmlFilename+" exists. Nothing will be created.");
347 				return;
348 			}
349 			componentInstanceInputStream = TemplateUtils.getTemplate(getClass(), "component-template.xml");
350 
351 			Document pom;
352 			try {
353 				pom = XmlUtils.getDocumentBuilder().parse(componentInstanceInputStream);
354 			} catch (Exception ex) {
355 				throw new IllegalStateException(ex);
356 			}
357 
358 			Element rootElement = (Element) pom.getFirstChild();
359 			XmlUtils.findFirstElementByName("guid", rootElement).setTextContent(componentInstanceName);
360 			XmlUtils.findFirstElementByName("title", rootElement).setTextContent(componentInstanceName);
361 			XmlUtils.findFirstElementByName("description", rootElement).setTextContent(componentInstanceName);
362 			XmlUtils.findFirstElementByName("url", rootElement).setTextContent(componentType);
363 			XmlUtils.findFirstElementByName("scope", rootElement).setTextContent(scope);
364 			XmlUtils.findFirstElementByName("source-id", rootElement).setTextContent(sourceId);
365 			XmlUtils.findFirstElementByName("region-id", rootElement).setTextContent(regionId);
366 
367 			MutableFile mutableFile = fileManager.createFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename));
368 			XmlUtils.writeXml(mutableFile.getOutputStream(), pom);
369 
370 			fileManager.scan();
371 
372 		} else if ( scope.equals("template") ){
373 			String templateInstanceName = pageOperations.getTemplateInstance(pageId);
374 			if ( templateInstanceName.equals("") ) {
375 				logger.warning("Can't file template instance for template scope component");
376 				return;
377 			} else {
378 				FileDetails templateInstanceXml = templateOperations.findSurfTemplateInstanceByName(templateInstanceName);
379 				componentInstanceInputStream = fileManager.getInputStream(templateInstanceXml.getCanonicalPath());
380 				Document pom;
381 				try {
382 					pom = XmlUtils.getDocumentBuilder().parse(componentInstanceInputStream);
383 				} catch (Exception ex) {
384 					throw new IllegalStateException(ex);
385 				}
386 				ComponentConfigUtils.updateComponentConfig(pom, regionId, componentType);
387 				MutableFile mutableFile = fileManager.updateFile(templateInstanceXml.getCanonicalPath());
388 				XmlUtils.writeXml(mutableFile.getOutputStream(), pom);
389 
390 				fileManager.scan();
391 			}
392 		} else if (scope.equals("page") ) {
393 			componentInstanceInputStream = fileManager.getInputStream(pageXml.getCanonicalPath());
394 			Document pom;
395 			try {
396 				pom = XmlUtils.getDocumentBuilder().parse(componentInstanceInputStream);
397 			} catch (Exception ex) {
398 				throw new IllegalStateException(ex);
399 			}
400 			ComponentConfigUtils.updateComponentConfig(pom, regionId, componentType);
401 			MutableFile mutableFile = fileManager.updateFile(pageXml.getCanonicalPath());
402 			XmlUtils.writeXml(mutableFile.getOutputStream(), pom);
403 			fileManager.scan();
404 		} else {
405 			logger.warning("Unsupported scope type "+scope);
406 			return;
407 		}
408 
409 		if ( options!=null && ! options.equals("") ) {
410 			// Do something with the options
411 		}
412 
413 		return;
414 	}
415 	/**
416 	 * Adds a new resource to the component configuration xml.
417 	 * The format of attribute list looks like attr1:val1|attr2:val2|attr3:val3 .
418 	 * @param componentName Component name.
419 	 * @param attributeList List of attributes for the new resource.
420 	 * @param contentBody Resource text content.
421 	 */
422 	public void createComponentResource(String componentName,String attributeList, String contentBody) {
423 		Assert.hasText(componentName, "Component instance name required");
424 		Assert.hasText(contentBody, "Content body required");
425 		if (!isSurfComponentAvailable(componentName)){
426 			logger.warning("Component "+componentName+" doesn't exist");
427 		}
428 		//Get hold of the content instance xml file.
429 		String componentInstanceXmlFilename = Constants.SURF_SITEDATA_COMPONENT_CP+componentName+".xml";
430 
431 		InputStream componentInstanceInputStream = fileManager.getInputStream(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename));
432 		Document pom;
433 		try {
434 			pom = XmlUtils.getDocumentBuilder().parse(componentInstanceInputStream);
435 		} catch (Exception ex) {
436 			throw new IllegalStateException(ex);
437 		}
438 
439 		Element rootElement = (Element) pom.getFirstChild();
440 
441 		Element resourcesElement = XmlUtils.findFirstElementByName("resources", rootElement);
442 		if (resourcesElement == null ) {
443 			resourcesElement = pom.createElement("resources");
444 			rootElement.appendChild(resourcesElement);
445 		}
446 
447 		Element newResourceElement = pom.createElement("resource");
448 		if (attributeList!=null && !attributeList.equals("")) {
449 			Hashtable<String,String> attrList = parseAttributeList (attributeList);
450 			for (String key : attrList.keySet() ) {
451 				newResourceElement.setAttribute(key, attrList.get(key));
452 			}
453 		}
454 
455 		newResourceElement.setTextContent(contentBody);
456 
457 		resourcesElement.appendChild(newResourceElement);
458 
459 		MutableFile mutableFile = fileManager.updateFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename));
460 		XmlUtils.writeXml(mutableFile.getOutputStream(), pom);
461 
462 		fileManager.scan();
463 
464 		try {
465 			componentInstanceInputStream.close();
466 		} catch (Exception ex) {
467 			throw new IllegalStateException(ex);
468 		}
469 
470 		return;
471 	}
472 
473 	/**
474 	 * Adds new properties to the component configuration xml.
475 	 * The format of input string looks like name1:val1|name2:val2|name3:val3 .
476 	 * @param componentName Component name.
477 	 * @param propertyList List of new properties.
478 	 */
479 	public void createComponentProperty(String componentName,String propertyList) {
480 		Assert.hasText(componentName, "Component instance name required");
481 		Assert.hasText(propertyList, "Property list required");
482 		if (!isSurfComponentAvailable(componentName)){
483 			logger.warning("Component "+componentName+" doesn't exist");
484 		}
485 		//Get hold of the content instance xml file.
486 		String componentInstanceXmlFilename = Constants.SURF_SITEDATA_COMPONENT_CP+componentName+".xml";
487 
488 		InputStream componentInstanceInputStream = fileManager.getInputStream(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename));
489 		Document pom;
490 		try {
491 			pom = XmlUtils.getDocumentBuilder().parse(componentInstanceInputStream);
492 		} catch (Exception ex) {
493 			throw new IllegalStateException(ex);
494 		}
495 
496 		Element rootElement = (Element) pom.getFirstChild();
497 
498 		Element propertiesElement = XmlUtils.findFirstElementByName("properties", rootElement);
499 		if (propertiesElement == null ) {
500 			propertiesElement = pom.createElement("properties");
501 			rootElement.appendChild(propertiesElement);
502 		}
503 
504 		if (propertyList!=null && !propertyList.equals("")) {
505 			Hashtable<String,String> propList = parseAttributeList (propertyList);
506 			for (String key : propList.keySet() ) {
507 				Element newPropElement = pom.createElement(key);
508 				newPropElement.setTextContent(propList.get(key));
509 				propertiesElement.appendChild(newPropElement);
510 			}
511 		}
512 
513 		MutableFile mutableFile = fileManager.updateFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename));
514 		XmlUtils.writeXml(mutableFile.getOutputStream(), pom);
515 
516 		fileManager.scan();
517 		return;
518 	}
519 
520 	/**
521 	 * Returns component name.
522 	 * @param pageInstanceName Page instance name.
523 	 * @param templateInstanceName Template instance name.
524 	 * @param regionId Region id.
525 	 * @param scope Region scope.
526 	 * @return Component name.
527 	 */
528 	public String getComponentInstanceName(String pageInstanceName, String templateInstanceName,String regionId, String scope) {
529 
530 		String componentInstanceName = "";
531 
532 		if ( scope.equals("global") ) {
533 			componentInstanceName = "global."+regionId;
534 		} else if ( scope.equals("template") ){
535 			if ( templateInstanceName.equals("") ) {
536 				logger.warning("For template scope component, you must specify template instance name");
537 				return null;
538 			} else {
539 				componentInstanceName = "template."+regionId+"."+templateInstanceName;
540 			}
541 		} else if (scope.equals("page") ) {
542 			if ( pageInstanceName == null || templateInstanceName.equals("") ) {
543 				logger.warning("For page scope component, you must specify page name");
544 				return null;
545 			} else {
546 				componentInstanceName = "page."+regionId+"."+pageInstanceName;
547 			}
548 		} else {
549 			logger.warning("Unsupported scope type "+scope);
550 			return null;
551 		}
552 
553 		return componentInstanceName;
554 	}
555 
556 	/**
557 	 * Returns component url.
558 	 * @param instanceName Component instance.
559 	 * @return Component url.
560 	 */
561 	public String getComponentUrl(String instanceName){
562 		//Get hold of the content instance xml file.
563 		String componentInstanceXmlFilename = Constants.SURF_SITEDATA_COMPONENT_CP+instanceName+".xml";
564 
565 		String 	componentInstanceXmlFilePath = pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, componentInstanceXmlFilename);
566 		if (!fileManager.exists(componentInstanceXmlFilePath))
567 			return null;
568 		InputStream componentInstanceInputStream = fileManager.getInputStream(componentInstanceXmlFilePath);
569 		Document doc;
570 		try {
571 			doc = XmlUtils.getDocumentBuilder().parse(componentInstanceInputStream);
572 		} catch (Exception ex) {
573 			throw new IllegalStateException(ex);
574 		}
575 
576 		Element rootElement = (Element) doc.getFirstChild();
577 		if ( rootElement!=null ) {
578 			return XmlUtils.findFirstElementByName("url", rootElement).getTextContent();
579 		}else{
580 			return null;
581 		}
582 	}
583 
584 	/**
585 	 * Utility method for parsing attribute list.
586 	 * @param attributeStr Attribute list string.
587 	 * @return List of attributes.
588 	 */
589 	private Hashtable<String,String> parseAttributeList (String attributeStr) {
590 		// Input string looks like attr1:value1|attr2:value2
591 		Hashtable<String,String> attributeList = new Hashtable<String,String>();
592 		for (String pair : attributeStr.split("\\|")) {
593 			if (pair.indexOf(":") != -1) {
594 				String[] temp = pair.split(":",2);
595 				if (temp[1].startsWith("\"") && temp[1].endsWith("\""))
596 					temp[1]=temp[1].substring(1,temp[1].length()-1);
597 				attributeList.put(temp[0].trim(),temp[1].trim());
598 			}
599 		}
600 		return attributeList;
601 	}
602 }