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.page;
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.template.TemplateOperations;
31  import org.springframework.roo.addon.surf.util.SurfUtils;
32  import org.springframework.roo.file.monitor.event.FileDetails;
33  import org.springframework.roo.metadata.MetadataService;
34  import org.springframework.roo.process.manager.FileManager;
35  import org.springframework.roo.process.manager.MutableFile;
36  import org.springframework.roo.project.Path;
37  import org.springframework.roo.project.PathResolver;
38  import org.springframework.roo.project.ProjectOperations;
39  import org.springframework.roo.support.lifecycle.ScopeDevelopment;
40  import org.springframework.roo.support.util.Assert;
41  import org.springframework.roo.support.util.TemplateUtils;
42  import org.springframework.roo.support.util.XmlUtils;
43  import org.w3c.dom.Document;
44  import org.w3c.dom.Element;
45  
46  /**
47   * Provides Surf Page related operations.
48   *
49   * @author Yong Qu
50   * @since 1.0
51   */
52  @ScopeDevelopment
53  public class PageOperations {
54  
55  	Logger logger = Logger.getLogger(PageOperations.class.getName());
56  
57  	private FileManager fileManager;
58  	private PathResolver pathResolver;
59  	private MetadataService metadataService;
60  	private ProjectOperations projectOperations;
61  
62  	private SurfOperations surfOperations;
63  	private String pageXmlRootPath;
64  
65  	/**
66  	 * @param fileManager
67  	 * @param pathResolver
68  	 * @param metadataService
69  	 * @param projectOperations
70  	 */
71  	public PageOperations(FileManager fileManager, PathResolver pathResolver, MetadataService metadataService, ProjectOperations projectOperations) {
72  		Assert.notNull(fileManager, "File manager required");
73  		Assert.notNull(pathResolver, "Path resolver required");
74  		Assert.notNull(metadataService, "Metadata service required");
75  		Assert.notNull(projectOperations, "Project operations required");
76  
77  		this.fileManager = fileManager;
78  		this.pathResolver = pathResolver;
79  		this.metadataService = metadataService;
80  		this.projectOperations = projectOperations;
81  
82  		this.surfOperations = new SurfOperations(fileManager, pathResolver, metadataService, projectOperations);
83  		this.pageXmlRootPath = pathResolver.getRoot(Path.SRC_MAIN_WEBAPP) + "/"+Constants.WEB_INF;
84  	}
85  
86  
87  
88  	/**
89  	 * Checks if page related operations are available.
90  	 * @return true if page related operations are available
91  	 */
92  	public boolean isPageOperationAvailable() {
93  		return surfOperations.isManageSurfAvailable();
94  	}
95  
96  	/**
97  	 * Creates a new Surf page using a specified template instance or template.
98  	 * @param pageId Page Id.
99  	 * @param pagePath Page path.
100 	 * @param templateInstance Name of the template instance for creating the new page.
101 	 * @param templatePath Path of the template for creating the new page.
102 	 * @param urls Page urls.
103 	 * @param title Page title.
104 	 */
105 	public void createPage(String pageId, String pagePath, String templateInstance,String templatePath,String urls,String title) {
106 
107 		Assert.hasText(pageId, "Page id required.");
108 		Assert.hasText(pagePath, "Page path required.");
109 
110 		// Get the full path.
111 		if (pagePath.equals("pages")) {
112 			pagePath = pagePath+File.separator+pageId+File.separator+pageId;
113 		} else {
114 			pagePath = pagePath+File.separator+pageId;
115 		}
116 		
117 		// This will make sure the user input path will be valid.
118 		pagePath = pagePath.replace("/", File.separator).replace("\\", File.separator);
119 		
120 		// Get template name from template path
121 		String templateName = SurfUtils.getNameFromPath(templatePath);
122 
123 		// Check if the page with same path exists
124 		if (this.findSurfPageByPath(pagePath) != null) {
125 			//file exists, so nothing to do
126 			logger.warning("Page with path "+pagePath+" exists. Please select different path.");
127 			return;
128 		}
129 
130 		// Check if the page with same id exists
131 		if (this.findSurfPageById(pageId) != null) {
132 			//file exists, so nothing to do
133 			logger.warning("Page with id "+pageId+" exists. Please select different id.");
134 			return;
135 		}
136 
137 		TemplateOperations templateOperations = new TemplateOperations(fileManager, pathResolver, metadataService, projectOperations);
138 
139 		// Check if the page will be created from template instance.
140 		if ( templateInstance != null && !templateInstance.equals("")) {
141 			if (templateOperations.findSurfTemplateInstanceByName(templateInstance) == null) {
142 				// Template instance doesn't exist. Do a check on the template path input.
143 				if ( templatePath!= null && !templatePath.equals("") ) {
144 					// Check if the template exists.
145 					if ( templateOperations.findSurfTemplateByPath(templatePath) != null ) {
146 						// Template exists. Let us figure out where to put that template instance.
147 						// Template instance will be placed in the template directory.
148 						// For instance name, if the templateInstance is set, we will use that as the name.
149 						// Otherwise, the template name will be used.
150 						String templateInstancePath = templatePath;
151 						if ( templateInstance != null && !templateInstance.equals("")){
152 							templateInstancePath = SurfUtils.getRelativePath(templatePath);
153 							logger.warning(templateInstancePath);
154 						}
155 						if (templateOperations.newTemplateInstance(templateInstance,templateInstancePath, templatePath)) {
156 							// We are good. New template instance is created.
157 							logger.warning("Template instance created.");
158 						} else {
159 							// We failed to create the instance.
160 							logger.warning("No new template instance will be created. Existing template instance will be used.");
161 						}
162 					}
163 				} else {
164 					logger.warning("Either a template instance or a template needs to be provided.");
165 					return;
166 				}
167 			}
168 		} else {
169 			// Template instance doesn't exist. Do a check on the template path input.
170 			if ( templatePath!= null && !templatePath.equals("") ) {
171 				// Check if template exists.
172 				if ( templateOperations.findSurfTemplateByPath(templatePath) != null ) {
173 					// Template exists. Let us figure out where to put that template instance.
174 					// Template instance will be placed in the template directory.
175 					// For instance name, if the templateInstance is set, we will use that as the name.
176 					// Otherwise, the template name will be used.
177 					String templateInstancePath = templatePath;
178 					if ( templateInstance != null && !templateInstance.equals("")){
179 						templateInstancePath = SurfUtils.getRelativePath(templatePath);
180 						logger.warning(templateInstancePath);
181 					} else {
182 						templateInstance = templateName;
183 					}
184 					if (templateOperations.newTemplateInstance(templateInstance,templateInstancePath, templatePath)) {
185 						// We are good. New template instance is created.
186 						logger.warning("New template instance created.");
187 					} else {
188 						// We failed to create the instance.
189 						logger.warning("No new template instance will be created. Existing template instance will be used.");
190 					}
191 				} else {
192 					logger.warning("Template "+templatePath+" doesn't exist.");
193 					return;
194 				}
195 			} else {
196 				logger.warning("Either template instance or template needs to be provided.");
197 				return;
198 			}
199 		}
200 
201 		String pageXmlFilename = Constants.WEB_INF+pagePath+".xml";
202 		InputStream templateInputStream = TemplateUtils.getTemplate(getClass(), "page-template.xml");
203 		Document page;
204 		try {
205 			page = XmlUtils.getDocumentBuilder().parse(templateInputStream);
206 		} catch (Exception ex) {
207 			throw new IllegalStateException(ex);
208 		}
209 
210 		Element rootElement = (Element) page.getFirstChild();
211 		XmlUtils.findFirstElementByName("template-instance", rootElement).setTextContent(templateInstance);
212 
213 		if (title!=null && !title.equals("")){
214 			XmlUtils.findFirstElementByName("title", rootElement).setTextContent(title);
215 		} else {
216 			XmlUtils.findFirstElementByName("title", rootElement).setTextContent(pageId);			
217 		}
218 
219 		XmlUtils.findFirstElementByName("id", rootElement).setTextContent(pageId);
220 
221 		//Process urls.
222 		if ( urls!= null && !urls.equals("")) {
223 			for (String url : urls.split(";|,|\\s+|\\|")) {
224 				Element urlElem = page.createElement("url");
225 				urlElem.setTextContent(url);
226 				rootElement.appendChild(urlElem);
227 			}
228 		}
229 
230 		MutableFile mutableFile = fileManager.createFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, pageXmlFilename));
231 		XmlUtils.writeXml(mutableFile.getOutputStream(), page);
232 		fileManager.scan();
233 
234 		try {
235 			templateInputStream.close();
236 		} catch (Exception ex) {
237 			throw new IllegalStateException(ex);
238 		}
239 
240 	}
241 
242 	/**
243 	 * Returns ids and paths of all Surf pages.
244 	 * @return Id/path list of all Surf pages..
245 	 */
246 	public SortedSet<String> listSurfPages() {
247 
248 		SortedSet<String> pageInfoList = new TreeSet<String>();
249 
250 		for (String pageId : getSurfPages().keySet()) {
251 			StringBuffer sb = new StringBuffer();
252 			sb.append("Id: ");
253 			sb.append(pageId);
254 			sb.append(" Path: ");
255 			sb.append( getSurfPages().get(pageId).getFile().getPath().substring(pageXmlRootPath.length()));
256 			pageInfoList.add(sb.toString());
257 		}
258 
259 		return pageInfoList;
260 	}
261 
262 	/**
263 	 * Returns true if the page id is available.
264 	 * @param pageId Page Id.
265 	 * @return True if the page id is available.
266 	 */
267 	public boolean isSurfPageAvailable(String pageId) {
268 		return getSurfPages().containsKey(pageId);
269 	}
270 
271 	/**
272 	 * Lists associated pages of a specified Surf page.
273 	 * @param pageId Page id.
274 	 * @return Lists of associated pages.
275 	 */
276 	public SortedSet<String> listSurfPageAssociations(String pageId) {
277 
278 		SortedSet<String> pageAssocsList = new TreeSet<String>();
279 		FileDetails page = this.findSurfPageById(pageId);
280 		Document pageDoc = SurfUtils.getSurfXMLDoc(fileManager, page);
281 
282 		for (Element assocElem : XmlUtils.findElements("/page/associations/page-association", pageDoc.getDocumentElement()) ) {
283 
284 			StringBuffer sb = new StringBuffer();
285 
286 			Element descIdElem = XmlUtils.findFirstElementByName("dest-id", assocElem);
287 			if ( descIdElem != null ) {
288 				sb.append("Page: ");
289 				sb.append(descIdElem.getTextContent().trim());
290 			}
291 
292 			Element typeElem = XmlUtils.findFirstElementByName("assoc-type", assocElem);
293 			if ( typeElem != null ) {
294 				sb.append(" Type: ");
295 				sb.append(typeElem.getTextContent().trim());
296 				pageAssocsList.add(sb.toString());
297 			}
298 		}
299 
300 		return pageAssocsList;
301 	}
302 
303 	/**
304 	 * Returns template instance path of a given page.
305 	 * @param pagePath Page path.
306 	 * @return Template instance path.
307 	 */
308 	public String getTemplateInstance(String pageName) {
309 		Assert.hasText(pageName, "Page path required");
310 
311 		FileDetails pageXml = findSurfPageById(pageName);
312 		if ( pageXml == null) {
313 			logger.warning("Page "+pageName+" doesn't exist.");
314 			return null;
315 		}
316 
317 		InputStream pageInputStream = fileManager.getInputStream(pageXml.getCanonicalPath());
318 		Document pom;
319 		try {
320 			pom = XmlUtils.getDocumentBuilder().parse(pageInputStream);
321 		} catch (Exception ex) {
322 			throw new IllegalStateException(ex);
323 		}
324 
325 		Element rootElement = (Element) pom.getFirstChild();
326 		String templateInstanceName = XmlUtils.findFirstElementByName("template-instance", rootElement).getTextContent();
327 
328 		try {
329 			pageInputStream.close();
330 		} catch (Exception ex) {
331 			throw new IllegalStateException(ex);
332 		}
333 
334 		return templateInstanceName;
335 
336 	}
337 
338 	/**
339 	 * Returns template path of the given template instance.
340 	 * @param instanceName Template instance name.
341 	 * @return Template path.
342 	 */
343 	public String getInstanceTemplatePath(String instanceName) {
344 		// Locate page instance
345 		String surfTemplatesRootPath = pathResolver.getRoot(Path.SRC_MAIN_WEBAPP) + "/"+Constants.WEB_INF;
346 		String antPath = (surfTemplatesRootPath+"**/"+instanceName+".xml").replace("/", File.separator);
347 
348 		SortedSet<FileDetails> entries = fileManager.findMatchingAntPath(antPath);
349 
350 		if (entries.size() == 0 ) {
351 			return null;
352 		} else {
353 
354 			Document pom;
355 
356 			InputStream templateInstanceInputStream = fileManager.getInputStream(entries.first().getCanonicalPath());
357 			try {
358 				pom = XmlUtils.getDocumentBuilder().parse(templateInstanceInputStream);
359 			} catch (Exception ex) {
360 				throw new IllegalStateException(ex);
361 			}
362 
363 			Element rootElement = (Element) pom.getFirstChild();
364 			String templateName = XmlUtils.findFirstElementByName("template-type", rootElement).getTextContent();
365 
366 			try {
367 				templateInstanceInputStream.close();
368 			} catch (Exception ex) {
369 				throw new IllegalStateException(ex);
370 			}
371 
372 			return templateName;
373 		}
374 	}
375 
376 	/**
377 	 * Returns template path of a Surf page with a given id.
378 	 * @param pageId Page Id.
379 	 * @return Page template path.
380 	 */
381 	public String getTemplatePath(String pageId) {
382 		String instanceName = this.getTemplateInstance(pageId);
383 		if ( instanceName == null ) {
384 			return null;
385 		} else {
386 			return this.getInstanceTemplatePath(instanceName);
387 		}
388 	}
389 
390 	/**
391 	 * Creates a new legacy page association which is stored as a seperated XML file.
392 	 * @param name Association name.
393 	 * @param srcPageId Source page id.
394 	 * @param desPageId Destination page id.
395 	 * @param type Association type.
396 	 */
397 	public void createPageAssociationAsFile(String name, String srcPageId, String desPageId,String type) {
398 
399 		Assert.hasText(srcPageId, "Source page id required");
400 		Assert.hasText(desPageId, "Destination page id required");
401 
402 		if ( name==null || name.equals("")) {
403 			name = srcPageId+"-"+desPageId;
404 		}
405 
406 		String pageAssocXmlFilename = Constants.SURF_SITEDATA_PAGE_ASSOC_CP+name+".xml";
407 
408 		if (fileManager.exists(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, pageAssocXmlFilename))) {
409 			//file exists, so nothing to do
410 			logger.warning("Page association "+pageAssocXmlFilename+" exists.");
411 			return;
412 		}
413 
414 		InputStream templateInstanceInputStream = TemplateUtils.getTemplate(getClass(), "page-association-template.xml");
415 		Document pom;
416 		try {
417 			pom = XmlUtils.getDocumentBuilder().parse(templateInstanceInputStream);
418 		} catch (Exception ex) {
419 			throw new IllegalStateException(ex);
420 		}
421 
422 		Element rootElement = (Element) pom.getFirstChild();
423 		XmlUtils.findFirstElementByName("source-id", rootElement).setTextContent(srcPageId);
424 		XmlUtils.findFirstElementByName("dest-id", rootElement).setTextContent(desPageId);
425 		XmlUtils.findFirstElementByName("assoc-type", rootElement).setTextContent(type);
426 
427 		MutableFile mutableFile = fileManager.createFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, pageAssocXmlFilename));
428 		XmlUtils.writeXml(mutableFile.getOutputStream(), pom);
429 
430 		fileManager.scan();
431 
432 		try {
433 			templateInstanceInputStream.close();
434 		} catch (Exception ex) {
435 			throw new IllegalStateException(ex);
436 		}
437 	}
438 
439 	/**
440 	 * Creates a new page association.
441 	 * @param name Association name.
442 	 * @param srcPageId Source page id.
443 	 * @param desPageId Destination page id.
444 	 * @param type Association type.
445 	 */
446 	public void createPageAssociation(String name, String srcPageId, String desPageId,String type) {
447 
448 		Assert.hasText(srcPageId, "Source page id required");
449 		Assert.hasText(desPageId, "Destination page id required");
450 
451 		FileDetails srcPage = this.findSurfPageById(srcPageId);
452 		if (srcPage ==null) {
453 			logger.warning("Source Page "+srcPageId+" doesn't exist.");
454 		} else {
455 			Document pageDoc = SurfUtils.getSurfXMLDoc(fileManager, srcPage);
456 			Element assocElem = XmlUtils.findFirstElement("/page/associations/page-association[dest-id='"+desPageId+"']",pageDoc.getDocumentElement());
457 			FileDetails destPage = this.findSurfPageById(desPageId);
458 			if (destPage == null) {
459 				logger.warning("Destination Page "+desPageId+" doesn't exist.");
460 			} else {
461 				if (assocElem != null) {
462 					logger.warning("The association exists.");
463 				} else {
464 					Element assocsElem = XmlUtils.findFirstElement("/page/associations",pageDoc.getDocumentElement());
465 					if (assocsElem == null) {
466 						assocsElem = pageDoc.createElement("associations");
467 						pageDoc.getFirstChild().appendChild(assocsElem);
468 					}
469 					assocElem = pageDoc.createElement("page-association");
470 					Element destIdElem = pageDoc.createElement("dest-id");
471 					destIdElem.setTextContent(desPageId);
472 					Element typeElem = pageDoc.createElement("assoc-type");
473 					typeElem.setTextContent(type);
474 					assocElem.appendChild(destIdElem);
475 					assocElem.appendChild(typeElem);
476 					assocsElem.appendChild(assocElem);
477 					XmlUtils.writeXml(fileManager.updateFile(srcPage.getCanonicalPath()).getOutputStream(), pageDoc);
478 					fileManager.scan();
479 				}
480 			}
481 		}
482 
483 	}
484 	/**
485 	 * Find Surf page by path.
486 	 * @param path Page path.
487 	 * @return Surf page.
488 	 */
489 	public FileDetails findSurfPageByPath(String path) {
490 		String antPath = (this.pageXmlRootPath+path+".xml").replace("/", File.separator);
491 		SortedSet<FileDetails> entries = fileManager.findMatchingAntPath(antPath);
492 		if (entries.size()==0 ){
493 			//Also check the legacy directory for Surf pages.
494 			String surfTemplatesRootPath = pathResolver.getRoot(Path.SRC_MAIN_WEBAPP) + "/" + Constants.SURF_SITEDATA_PAGE_CP;
495 			antPath = (surfTemplatesRootPath+path+".xml").replace("/", File.separator);
496 			entries = fileManager.findMatchingAntPath(antPath);
497 		}
498 		if (entries.size()==0 ){
499 			return null;
500 		}else{
501 			for (FileDetails file: entries) {
502 				if (SurfUtils.fileContainsString(fileManager.getInputStream(file.getCanonicalPath()), "<page>"))
503 					return file;
504 			}
505 			return null;
506 		}
507 	}
508 
509 	/**
510 	 * Finds Surf page by id.
511 	 * @param pageId Page Id
512 	 * @return Surf page.
513 	 */
514 	public FileDetails findSurfPageById(String pageId) {
515 		String antPath = (this.pageXmlRootPath+"**/"+pageId+".xml").replace("/", File.separator);
516 		SortedSet<FileDetails> entries = fileManager.findMatchingAntPath(antPath);
517 		if (entries.size()==0 ){
518 			return null;
519 		}else{
520 			for (FileDetails file: entries) {
521 				if (SurfUtils.fileContainsString(fileManager.getInputStream(file.getCanonicalPath()), "<page>"))
522 					return file;
523 			}
524 			return null;
525 		}
526 	}
527 
528 	/**
529 	 * Returns PageId/FileDetails pairs of Surf pages.
530 	 * @return List of PageId/FileDetails pairs of Surf pages.
531 	 */
532 	public Hashtable <String,FileDetails> getSurfPages() {
533 
534 		String antPath = (pageXmlRootPath + "**/*.xml").replace("/", File.separator);
535 		SortedSet<FileDetails> entries = fileManager.findMatchingAntPath(antPath);
536 
537 		Hashtable <String,FileDetails> pageList = new Hashtable <String,FileDetails>();
538 
539 		for (FileDetails fileIdentifier : entries) {
540 			if ( SurfUtils.checkSurfXMLType(fileManager, fileIdentifier.getCanonicalPath(),"page") ) {
541 				String pageId = fileIdentifier.getFile().getName().replace(".xml","");
542 				pageList.put(pageId,fileIdentifier);
543 			}
544 		}
545 
546 		return pageList;
547 	}
548 
549 
550 
551 	public String getPageXmlRootPath() {
552 		return pageXmlRootPath;
553 	}
554 
555 }