001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: */
013: /*
014: * Created on Jun 21, 2005
015: *
016: * TODO To change the template for this generated file go to
017: * Window - Preferences - Java - Code Style - Code Templates
018: */
019: package org.pentaho.repository.filebased.solution;
020:
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.FileNotFoundException;
024: import java.io.FileOutputStream;
025: import java.io.FilenameFilter;
026: import java.io.IOException;
027: import java.net.URL;
028: import java.net.URLClassLoader;
029: import java.util.ArrayList;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.ResourceBundle;
033: import java.util.StringTokenizer;
034:
035: import org.apache.commons.lang.StringUtils;
036: import org.dom4j.Document;
037: import org.dom4j.DocumentHelper;
038: import org.dom4j.Element;
039: import org.dom4j.Node;
040: import org.pentaho.core.repository.ISolutionRepository;
041: import org.pentaho.core.repository.SolutionRepositoryBase;
042: import org.pentaho.core.runtime.IRuntimeContext;
043: import org.pentaho.core.session.IPentahoSession;
044: import org.pentaho.core.solution.ActionResource;
045: import org.pentaho.core.solution.IActionResource;
046: import org.pentaho.core.solution.IActionSequence;
047: import org.pentaho.core.solution.ISolutionFile;
048: import org.pentaho.core.solution.SequenceDefinition;
049: import org.pentaho.core.solution.SolutionReposUtil;
050: import org.pentaho.core.solution.SolutionReposUtil.ISolutionFilter;
051: import org.pentaho.core.system.PentahoSystem;
052: import org.pentaho.core.util.XmlHelper;
053: import org.pentaho.messages.Messages;
054: import org.pentaho.util.FileHelper;
055:
056: import com.pentaho.repository.subscribe.ISubscriptionRepository;
057:
058: /**
059: * @author James Dixon TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
060: */
061: public class SolutionRepository extends SolutionRepositoryBase
062: implements ISolutionFilter {
063: /**
064: *
065: */
066: private static final long serialVersionUID = -8270135463210017284L;
067:
068: private boolean useActionSequenceCaching = false;
069:
070: public SolutionRepository() {
071: init();
072: }
073:
074: public void init() {
075: super .init();
076:
077: String flag = PentahoSystem.getSystemSetting(
078: "filebased-solution-cache", "false"); //$NON-NLS-1$ //$NON-NLS-2$
079: try {
080: useActionSequenceCaching = Boolean.getBoolean(flag);
081: } catch (Exception e) {
082: useActionSequenceCaching = false;
083: }
084: }
085:
086: public ClassLoader getClassLoader(String path) {
087: File localeDir = new File(PentahoSystem.getApplicationContext()
088: .getSolutionPath(path));
089: try {
090: URLClassLoader loader = new URLClassLoader(
091: new URL[] { localeDir.toURL() });
092: return loader;
093: } catch (Exception e) {
094: }
095: return null;
096: }
097:
098: public IActionSequence getActionSequence(String solutionName,
099: String actionPath, String sequenceName,
100: int localLoggingLevel, int actionOperation) {
101: String action;
102:
103: IActionSequence actionSequence = null;
104: if (actionPath != null && !"".equals(actionPath)) { //$NON-NLS-1$
105: action = solutionName + File.separator + actionPath
106: + File.separator + sequenceName;
107: } else {
108: action = solutionName + File.separator + sequenceName;
109: }
110:
111: if (useActionSequenceCaching) {
112: actionSequence = (IActionSequence) getRepositoryObjectFromCache(action);
113: }
114: if (actionSequence != null) {
115: return actionSequence;
116: }
117: Document actionSequenceDocument = getSolutionDocument(action);
118: if (actionSequenceDocument == null) {
119: return null;
120: }
121:
122: actionSequence = SequenceDefinition.ActionSequenceFactory(
123: actionSequenceDocument, sequenceName, actionPath,
124: solutionName, this , PentahoSystem
125: .getApplicationContext(), localLoggingLevel);
126: if (actionSequence == null) {
127: return null;
128: }
129:
130: if (useActionSequenceCaching) {
131: putRepositoryObjectInCache(action, actionSequence);
132: }
133:
134: return actionSequence;
135: }
136:
137: public Document getSolutionDocument(String solutionName,
138: String actionPath, String actionName) {
139: return getSolutionDocument(solutionName + File.separator
140: + actionPath + File.separator + actionName);
141: }
142:
143: public Document getSolutionDocument(String documentPath) {
144: // TODO: caching
145: File file = getFile(documentPath, false);
146: if (file == null) {
147: return null;
148: }
149: Document document = XmlHelper.getDocFromFile(file);
150: if (document == null && file.exists()) {
151: // the document exists but cannot be parsed
152: error(Messages
153: .getString(
154: "SolutionRepository.ERROR_0009_INVALID_DOCUMENT", documentPath)); //$NON-NLS-1$
155: return null;
156: }
157: localizeDoc(document, new FileSolutionFile(file,
158: ((FileSolutionFile) getRootFolder()).getFile()));
159: return document;
160: }
161:
162: private File getFile(IRuntimeContext runtimeContext, String path) {
163: if (runtimeContext == null) {
164: error(Messages
165: .getErrorString("SolutionRepository.ERROR_0002_NULL_RUNTIME_CONTEXT")); //$NON-NLS-1$
166: return null;
167: }
168: File f = getFile(runtimeContext.getSolutionName()
169: + File.separator + path, false);
170: if (!f.exists()) {
171: error(Messages
172: .getErrorString(
173: "SolutionRepository.ERROR_0003_NULL_SOLUTION_FILE", path)); //$NON-NLS-1$
174: return null;
175: }
176: // TODO: caching
177: if (debug)
178: debug(Messages
179: .getString(
180: "SolutionRepository.DEBUG_FILE_PATH", f.getAbsolutePath())); //$NON-NLS-1$
181: return f;
182: }
183:
184: public String getActionDefinition(IRuntimeContext runtimeContext,
185: String actionPath) {
186: // TODO: caching
187: if ((runtimeContext == null)
188: || (runtimeContext.getInstanceId() == null)
189: || (runtimeContext.getActionName() == null)) {
190: error(Messages
191: .getErrorString("SolutionRepository.ERROR_0004_INVALID_CONTEXT")); //$NON-NLS-1$
192: }
193: genLogIdFromInfo(runtimeContext.getInstanceId(), LOG_NAME,
194: runtimeContext.getActionName());
195: File f = getFile(runtimeContext, actionPath);
196: if (f == null) {
197: error(Messages
198: .getErrorString("SolutionRepository.ERROR_0005_INVALID_SOLUTION_FILE") + actionPath); //$NON-NLS-1$
199: }
200: return FileHelper.getStringFromFile(f);
201: }
202:
203: public Document getActionDefinitionDocument(
204: IRuntimeContext runtimeContext, String actionPath) {
205: // TODO: caching
206: genLogIdFromInfo(runtimeContext.getInstanceId(), LOG_NAME,
207: runtimeContext.getActionName());
208: File f = getFile(runtimeContext, actionPath);
209: if (f == null) {
210: return null;
211: }
212: return XmlHelper.getDocFromFile(f);
213: }
214:
215: // Old prototype code that needs to be redone somehow...
216: public void reloadSolutionRepository(IPentahoSession localSession,
217: final int localLoggingLevel) {
218: if (isCachingAvailable()) {
219: File rootDir = getFile("", false); //$NON-NLS-1$
220: Document repository = DocumentHelper.createDocument();
221: Element rootNode = repository.addElement("repository"); //$NON-NLS-1$
222: processDir(rootNode, rootDir, null, 0,
223: ISolutionRepository.ACTION_ADMIN);
224: resetRepository();
225: putRepositoryObjectInCache(getRepositoryKey(), repository);
226: }
227: }
228:
229: private void processDir(Element parentNode, File parentDir,
230: String solutionId, int pathIdx, int actionOperation) {
231: File files[] = parentDir.listFiles();
232: // first process the directories
233: for (int idx = 0; idx < files.length; idx++) {
234: if (!files[idx].isDirectory()) {
235: String fileName = files[idx].getName();
236: if (fileName.equals("Entries") || fileName.equals("Repository") || fileName.equals("Root")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
237: // ignore any CVS files
238: continue;
239: }
240: String solutionPath = files[idx].getAbsolutePath()
241: .substring(rootPath.length());
242: if (fileName.toLowerCase().endsWith(".url")) { //$NON-NLS-1$
243: addUrlToRepository(files[idx], parentNode,
244: solutionPath);
245: }
246: if (!fileName.toLowerCase().endsWith(".xaction") && !fileName.toLowerCase().endsWith(".xml")) { //$NON-NLS-1$ //$NON-NLS-2$
247: // ignore any non-XML files
248: continue;
249: }
250: if (fileName.toLowerCase().equals(
251: SolutionRepositoryBase.INDEX_FILENAME)) {
252: // index.xml files are handled in the directory loop below
253: continue;
254: }
255: String path = files[idx].getAbsolutePath().substring(
256: pathIdx);
257: if (!path.equals(fileName)) {
258: path = path.substring(0, path.length()
259: - fileName.length() - 1);
260: // windows \ characters in the path gets messy in urls, so
261: // switch them to /
262: path = path.replace('\\', '/');
263: } else {
264: path = ""; //$NON-NLS-1$
265: }
266: if (fileName.toLowerCase().endsWith(".xaction")) { //$NON-NLS-1$
267: // create an action sequence document from this
268: info(Messages
269: .getString(
270: "SolutionRepository.DEBUG_ADDING_ACTION", fileName)); //$NON-NLS-1$
271: IActionSequence actionSequence = getActionSequence(
272: solutionId, path, fileName, loggingLevel,
273: actionOperation);
274: if (actionSequence == null) {
275: error(Messages
276: .getErrorString(
277: "SolutionRepository.ERROR_0006_INVALID_SEQUENCE_DOCUMENT", fileName)); //$NON-NLS-1$
278: } else {
279: addToRepository(actionSequence, parentNode,
280: files[idx]);
281: }
282: }
283: }
284: }
285: for (int idx = 0; idx < files.length; idx++) {
286: if (files[idx].isDirectory()
287: && (!files[idx].getName()
288: .equalsIgnoreCase("system")) && (!files[idx].getName().equalsIgnoreCase("CVS")) && (!files[idx].getName().equalsIgnoreCase(".svn"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
289: Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
290: dirNode.addAttribute("type", FileInfo.FILE_TYPE_FOLDER); //$NON-NLS-1$
291: // TODO read this from the directory index file
292: String this Solution;
293: String path = ""; //$NON-NLS-1$
294: if (solutionId == null) {
295: this Solution = files[idx].getName();
296: pathIdx = rootPath.length()
297: + File.separator.length()
298: + this Solution.length();
299: } else {
300: this Solution = solutionId;
301: path = files[idx].getAbsolutePath().substring(
302: pathIdx);
303: // windows \ characters in the path gets messy in urls, so
304: // switch them to /
305: path = path.replace('\\', '/');
306: dirNode.addElement("path").setText(path); //$NON-NLS-1$
307: }
308: File indexFile = new File(files[idx],
309: SolutionRepositoryBase.INDEX_FILENAME);
310: Document indexDoc = null;
311: if (indexFile.exists()) {
312: indexDoc = getSolutionDocument(this Solution, path,
313: SolutionRepositoryBase.INDEX_FILENAME);
314: }
315: if (indexDoc != null) {
316: addIndexToRepository(indexDoc, files[idx], dirNode,
317: path, this Solution);
318: } else {
319: dirNode.addAttribute("visible", "false"); //$NON-NLS-1$ //$NON-NLS-2$
320: String dirName = files[idx].getName();
321: dirNode.addAttribute(
322: "name", XmlHelper.encode(dirName)); //$NON-NLS-1$
323: dirNode.addElement("title").setText(dirName); //$NON-NLS-1$
324: }
325: processDir(dirNode, files[idx], this Solution, pathIdx,
326: actionOperation);
327: } else if (solutionId == null
328: && files[idx].getName().equalsIgnoreCase(
329: SolutionRepositoryBase.INDEX_FILENAME)) {
330: Document indexDoc = null;
331: indexDoc = getSolutionDocument(
332: "", "", SolutionRepositoryBase.INDEX_FILENAME); //$NON-NLS-1$ //$NON-NLS-2$
333: if (indexDoc != null) {
334: addIndexToRepository(indexDoc, parentDir,
335: parentNode, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
336: }
337: }
338: }
339: }
340:
341: // TODO sbarkdull, needs to be refactored, consider if
342: // how it should work with/, etc. XmlHelper getLocalizedFile
343: protected String getLocaleString(String key, String baseName,
344: ISolutionFile baseFile) {
345: File searchDir = ((FileSolutionFile) baseFile.retrieveParent())
346: .getFile();
347: try {
348: boolean searching = true;
349: while (searching) {
350: // look to see if this exists
351: URLClassLoader loader = new URLClassLoader(
352: new URL[] { searchDir.toURL() });
353: String localeText = null;
354: try {
355: ResourceBundle rb = ResourceBundle.getBundle(
356: baseName, getLocale(), loader);
357: localeText = rb.getString(key.substring(1));
358: } catch (Exception e) {
359: // couldn't load bundle, move along
360: }
361: if (localeText != null) {
362: return localeText;
363: }
364: // if we get to here, we couldn't use the resource bundle to find the string, so we will use this another approach
365: // change the basename to messages (messages.properties) and go up a directory in our searching
366: if (searching) {
367: if (!baseName.equals("messages")) { //$NON-NLS-1$
368: baseName = "messages"; //$NON-NLS-1$
369: } else {
370: if (searchDir.equals(rootFile)) {
371: searching = false;
372: } else {
373: searchDir = searchDir.getParentFile();
374: }
375: }
376: }
377: }
378: return null;
379: } catch (Exception e) {
380: error(
381: Messages
382: .getErrorString(
383: "SolutionRepository.ERROR_0007_COULD_NOT_READ_PROPERTIES", baseFile.getFullPath()), e); //$NON-NLS-1$
384: }
385: return null;
386: }
387:
388: private void addIndexToRepository(Document indexDoc,
389: File directoryFile, Element directoryNode, String path,
390: String solution) {
391: // TODO see if there is a localized attribute file for the current
392: // locale
393: String dirName = getValue(
394: indexDoc,
395: "/index/name", directoryFile.getName().replace('_', ' ')); //$NON-NLS-1$
396: String description = getValue(indexDoc,
397: "/index/description", ""); //$NON-NLS-1$ //$NON-NLS-2$
398: String iconPath = getValue(indexDoc, "/index/icon", ""); //$NON-NLS-1$ //$NON-NLS-2$
399: String displayType = getValue(indexDoc,
400: "/index/display-type", "icons"); //$NON-NLS-1$ //$NON-NLS-2$
401: boolean visible = getValue(indexDoc, "/index/visible", "false").equalsIgnoreCase("true"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
402:
403: if (solution == null) {
404: directoryNode.addAttribute("name", solution); //$NON-NLS-1$
405: } else {
406: directoryNode.addAttribute(
407: "name", XmlHelper.encode(directoryFile.getName())); //$NON-NLS-1$
408: }
409: directoryNode.addElement("title").setText(dirName); //$NON-NLS-1$
410: // directoryNode.addElement( "path" ).setText( path ); //$NON-NLS-1$
411: directoryNode.addAttribute("path", XmlHelper.encode(path)); //$NON-NLS-1$
412: directoryNode.addElement("description").setText(description); //$NON-NLS-1$
413: if (!StringUtils.isEmpty(iconPath)) {
414: String rolloverIconPath = null;
415: int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
416: if (rolloverIndex > -1) {
417: rolloverIconPath = iconPath
418: .substring(rolloverIndex + 1);
419: iconPath = iconPath.substring(0, rolloverIndex);
420: }
421: if (publishIcon(PentahoSystem.getApplicationContext()
422: .getSolutionPath(solution + File.separator + path),
423: iconPath)) {
424: directoryNode
425: .addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
426: } else {
427: directoryNode.addElement("icon").setText(iconPath); //$NON-NLS-1$
428: }
429: if (rolloverIconPath != null) {
430: if (publishIcon(PentahoSystem.getApplicationContext()
431: .getSolutionPath(
432: solution + File.separator + path),
433: rolloverIconPath)) {
434: directoryNode
435: .addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
436: } else {
437: directoryNode
438: .addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
439: }
440: }
441: }
442: directoryNode
443: .addAttribute("visible", Boolean.toString(visible)); //$NON-NLS-1$
444: directoryNode.addAttribute("displaytype", displayType); //$NON-NLS-1$
445: directoryNode.addElement("solution").setText(solution); //$NON-NLS-1$
446: }
447:
448: private void addUrlToRepository(File file, Element parentNode,
449: String solutionPath) {
450: // parse the .url file to get the contents
451: ActionResource urlResource = new ActionResource(file.getName(),
452: IActionResource.SOLUTION_FILE_RESOURCE,
453: "text/url", solutionPath); //$NON-NLS-1$
454: try {
455: String urlContent = getResourceAsString(urlResource);
456: StringTokenizer tokenizer = new StringTokenizer(urlContent,
457: "\n"); //$NON-NLS-1$
458: String url = null;
459: String title = file.getName();
460: String description = null;
461: String iconPath = null;
462: String target = null;
463: while (tokenizer.hasMoreTokens()) {
464: String line = tokenizer.nextToken();
465: int pos = line.indexOf('=');
466: if (pos > 0) {
467: String name = line.substring(0, pos);
468: String value = line.substring(pos + 1);
469: if ((value != null)
470: && (value.length() > 0)
471: && (value.charAt(value.length() - 1) == '\r')) {
472: value = value.substring(0, value.length() - 1);
473: }
474: if ("URL".equalsIgnoreCase(name)) { //$NON-NLS-1$
475: url = value;
476: }
477: if ("name".equalsIgnoreCase(name)) { //$NON-NLS-1$
478: title = value;
479: }
480: if ("description".equalsIgnoreCase(name)) { //$NON-NLS-1$
481: description = value;
482: }
483: if ("icon".equalsIgnoreCase(name)) { //$NON-NLS-1$
484: iconPath = value;
485: }
486: if ("target".equalsIgnoreCase(name)) { //$NON-NLS-1$
487: target = value;
488: }
489: }
490: }
491: if (url != null) {
492: // now create an entry for the database
493: Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
494: dirNode.addAttribute("type", FileInfo.FILE_TYPE_URL); //$NON-NLS-1$
495: dirNode.addElement("filename").setText(file.getName()); //$NON-NLS-1$
496: dirNode.addElement("title").setText(title); //$NON-NLS-1$
497: if (target != null) {
498: dirNode.addElement("target").setText(target); //$NON-NLS-1$
499: }
500: if (description != null) {
501: dirNode
502: .addElement("description").setText(description); //$NON-NLS-1$
503: }
504: if (iconPath != null && !iconPath.equals("")) { //$NON-NLS-1$
505: String rolloverIconPath = null;
506: int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
507: if (rolloverIndex > -1) {
508: rolloverIconPath = iconPath
509: .substring(rolloverIndex + 1);
510: iconPath = iconPath.substring(0, rolloverIndex);
511: }
512: if (publishIcon(file.getParentFile()
513: .getAbsolutePath(), iconPath)) {
514: dirNode
515: .addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
516: } else {
517: dirNode.addElement("icon").setText(iconPath); //$NON-NLS-1$
518: }
519: if (rolloverIconPath != null) {
520: if (publishIcon(PentahoSystem
521: .getApplicationContext()
522: .getSolutionPath(solutionPath),
523: rolloverIconPath)) {
524: dirNode
525: .addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
526: } else {
527: dirNode
528: .addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
529: }
530: }
531: }
532: dirNode.addElement("url").setText(url); //$NON-NLS-1$
533: dirNode.addAttribute("visible", "true"); //$NON-NLS-1$ //$NON-NLS-2$
534: dirNode.addAttribute(
535: "displaytype", FileInfo.FILE_DISPLAY_TYPE_URL); //$NON-NLS-1$
536: localizeDoc(dirNode, new FileSolutionFile(file,
537: ((FileSolutionFile) getRootFolder()).getFile()));
538: }
539: } catch (IOException e) {
540: }
541: }
542:
543: private void addToRepository(IActionSequence actionSequence,
544: Element parentNode, File file) {
545: Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
546: dirNode.addAttribute("type", FileInfo.FILE_TYPE_ACTIVITY); //$NON-NLS-1$
547: if (actionSequence.getSequenceName() == null
548: || actionSequence.getSolutionPath() == null
549: || actionSequence.getSolutionName() == null) {
550: error(Messages
551: .getString("SolutionRepository.ERROR_0008_ACTION_SEQUENCE_NAME_INVALID")); //$NON-NLS-1$
552: return;
553: }
554: dirNode
555: .addElement("filename").setText(actionSequence.getSequenceName()); //$NON-NLS-1$
556: dirNode
557: .addElement("path").setText(actionSequence.getSolutionPath()); //$NON-NLS-1$
558: dirNode
559: .addElement("solution").setText(actionSequence.getSolutionName()); //$NON-NLS-1$
560: String title = actionSequence.getTitle();
561: if (title == null) {
562: dirNode
563: .addElement("title").setText(actionSequence.getSequenceName()); //$NON-NLS-1$
564: } else {
565: dirNode.addElement("title").setText(title); //$NON-NLS-1$
566: }
567: String description = actionSequence.getDescription();
568: if (description == null) {
569: dirNode.addElement("description"); //$NON-NLS-1$
570: } else {
571: dirNode.addElement("description").setText(description); //$NON-NLS-1$
572: }
573: String author = actionSequence.getAuthor();
574: if (author == null) {
575: dirNode.addElement("author"); //$NON-NLS-1$
576: } else {
577: dirNode.addElement("author").setText(author); //$NON-NLS-1$
578: }
579: String iconPath = actionSequence.getIcon();
580: if (iconPath != null && !iconPath.equals("")) { //$NON-NLS-1$
581: String rolloverIconPath = null;
582: int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
583: if (rolloverIndex > -1) {
584: rolloverIconPath = iconPath
585: .substring(rolloverIndex + 1);
586: iconPath = iconPath.substring(0, rolloverIndex);
587: }
588: if (publishIcon(file.getParentFile().getAbsolutePath(),
589: iconPath)) {
590: dirNode
591: .addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
592: } else {
593: dirNode
594: .addElement("icon").setText(actionSequence.getIcon()); //$NON-NLS-1$
595: }
596: if (rolloverIconPath != null) {
597: if (publishIcon(PentahoSystem.getApplicationContext()
598: .getSolutionPath(
599: actionSequence.getSolutionName()
600: + File.separator
601: + actionSequence
602: .getSolutionPath()),
603: rolloverIconPath)) {
604: dirNode
605: .addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
606: } else {
607: dirNode
608: .addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
609: }
610: }
611: }
612: String displayType = actionSequence.getResultType();
613: if ((displayType == null)
614: || ("none".equalsIgnoreCase(displayType))) { //$NON-NLS-1$
615: // this should be hidden from users
616: dirNode.addAttribute("visible", "false"); //$NON-NLS-1$ //$NON-NLS-2$
617: } else {
618: dirNode.addAttribute("visible", "true"); //$NON-NLS-1$ //$NON-NLS-2$
619: dirNode.addAttribute("displaytype", displayType); //$NON-NLS-1$
620: }
621:
622: ISubscriptionRepository subscriptionRepository = PentahoSystem
623: .getSubscriptionRepository(getSession());
624: boolean subscribable = false;
625: if (subscriptionRepository != null) {
626: subscribable = subscriptionRepository
627: .getContentByActionReference(actionSequence
628: .getSolutionName()
629: + '/'
630: + actionSequence.getSolutionPath()
631: + '/' + actionSequence.getSequenceName()) != null;
632: }
633: dirNode
634: .addElement("properties").setText("subscribable=" + Boolean.toString(subscribable)); //$NON-NLS-1$ //$NON-NLS-2$
635:
636: }
637:
638: private boolean publishIcon(String dirPath, String iconPath) {
639: File iconSource = new File(dirPath + File.separator + iconPath);
640: if (iconSource.exists()) {
641: File tmpDir = getFile("system/tmp/icons", true); //$NON-NLS-1$
642: tmpDir.mkdirs();
643: File iconDestintation = new File(tmpDir.getAbsoluteFile()
644: + File.separator + iconPath);
645: if (iconDestintation.exists()) {
646: iconDestintation.delete();
647: }
648: try {
649: // create a byte array to hold the bits and nibbles
650: byte bytes[] = new byte[16384];
651: // read the file into the byte array
652: FileInputStream stream = new FileInputStream(iconSource);
653: FileOutputStream outputStream = new FileOutputStream(
654: iconDestintation);
655: try {
656: int numRead = 0;
657: while ((numRead = stream.read(bytes)) != -1) {
658: outputStream.write(bytes, 0, numRead);
659: outputStream.flush();
660: }
661: } finally {
662: outputStream.close();
663: stream.close();
664: }
665: } catch (FileNotFoundException e) {
666: // this one is not very likey
667: error(e.getLocalizedMessage());
668: } catch (IOException e) {
669: error(e.getLocalizedMessage());
670: }
671: return true;
672: } else {
673: return false;
674: }
675: }
676:
677: public Document getSolutions(String solutionName, String pathName,
678: int actionOperation, boolean visibleOnly) {
679: return getSolutions(actionOperation);
680: }
681:
682: public Document getSolutions(int actionOperation) {
683: Object cachedRepo = getRepositoryObjectFromCache(getRepositoryKey());
684: if (cachedRepo == null) {
685: reloadSolutionRepository(getSession(), loggingLevel);
686: cachedRepo = getRepositoryObjectFromCache(getRepositoryKey());
687: }
688: return (Document) cachedRepo;
689: }
690:
691: private Document getActionSequences(String solution, String path,
692: boolean subDirectories, boolean visibleOnly,
693: int actionOperation) {
694: List nodes;
695: if (solution == null) {
696: nodes = getSolutionNames(solution, path, actionOperation,
697: visibleOnly);
698: } else {
699: nodes = getFileListIterator(solution, path, subDirectories,
700: visibleOnly);
701: }
702: Document document = DocumentHelper.createDocument();
703: Element root = document.addElement("files"); //$NON-NLS-1$
704: Element pathNames = root.addElement("location"); //$NON-NLS-1$
705:
706: pathNames.setText(getPathNames(solution, path));
707:
708: Iterator nodeIterator = nodes.iterator();
709: while (nodeIterator.hasNext()) {
710: Node node = (Node) nodeIterator.next();
711: root.add((Node) node.clone());
712: }
713: return document;
714: }
715:
716: private String getPathNames(String solutionId, String path) {
717: Document repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
718: if (repository == null) {
719: reloadSolutionRepository(getSession(), loggingLevel);
720: repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
721: }
722: if (solutionId == null) {
723: return ""; //$NON-NLS-1$
724: }
725:
726: // TODO sbarkdull, extract to a method, this same code is repeated in this class
727: String xPath = "/repository/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" + XmlHelper.encode(solutionId) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
728:
729: if (path != null) {
730: String folders[] = path.split("/"); //$NON-NLS-1$
731: if (folders != null) {
732: for (int idx = 0; idx < folders.length; idx++) {
733: xPath += "/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" + XmlHelper.encode(folders[idx]) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
734: xPath += "[@visible=\"true\"]"; //$NON-NLS-1$
735: }
736: }
737: }
738:
739: StringBuffer sb = new StringBuffer();
740: List list = repository.selectNodes(xPath);
741: if (list != null && list.size() > 0) {
742: // grab the first one
743: Element node = (Element) list.get(0);
744: // walk up the ancestors
745: boolean done = false;
746: while (node != null && !done) {
747: Node titleNode = node.selectSingleNode("title"); //$NON-NLS-1$
748: if (titleNode != null) {
749: String name = titleNode.getText();
750: sb.insert(0, name + "/"); //$NON-NLS-1$
751: } else {
752: // if we don't have a title node then there is nothing more we can do to construct the path
753: done = true;
754: }
755: node = node.getParent();
756: }
757: }
758: return sb.toString();
759:
760: }
761:
762: private List getFileListIterator(String solutionId, String path,
763: boolean subDirectories, boolean visibleOnly) {
764: Document repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
765: if (repository == null) {
766: reloadSolutionRepository(getSession(), loggingLevel);
767: repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
768: }
769: String xPath;
770: if (solutionId == null) {
771: xPath = "/repository/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$
772: } else {
773: xPath = "/repository/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" + XmlHelper.encode(solutionId) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
774: }
775: if (path != null) {
776: String folders[] = path.split("/"); //$NON-NLS-1$
777: if (folders != null) {
778: for (int idx = 0; idx < folders.length; idx++) {
779: xPath += "/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" + XmlHelper.encode(folders[idx]) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
780: if (visibleOnly) {
781: xPath += "[@visible=\"true\"]"; //$NON-NLS-1$
782: }
783: }
784: }
785: }
786: if (subDirectories) {
787: xPath = "descendant-or-self::" + xPath; //$NON-NLS-1$
788: }
789: if (debug)
790: debug(Messages.getString(
791: "SolutionRepository.DEBUG_FILE_LIST_XPATH", xPath)); //$NON-NLS-1$
792: return repository.selectNodes(xPath);
793: }
794:
795: // TODO sbarkdull, this method does not belong here, but belongs in an XML utilities class, maybe XmlHelper?
796: public String getValue(Document doc, String xPath,
797: String defaultValue) {
798: if (doc != null) {
799: Node node = doc.selectSingleNode(xPath);
800: if (node == null) {
801: return defaultValue;
802: }
803: return node.getText();
804: }
805: return defaultValue;
806: }
807:
808: public Document getSolutionStructure(int actionOperation) {
809: Document document = DocumentHelper.createDocument();
810: File rootDir = getFile(EMPTY_STR, false);
811: Element root = document.addElement(ROOT_NODE_NAME)
812: .addAttribute(LOCATION_ATTR_NAME,
813: rootDir.getAbsolutePath());
814: processSolutionTree(root, rootDir);
815: return document;
816: }
817:
818: public Document getSolutionTree(int actionOperation,
819: ISolutionFilter filter) {
820: //return (SolutionReposUtil.getActionSequences(new FileSolutionFile(rootFile, rootFile), actionOperation));
821: return (SolutionReposUtil.processSolutionTree(
822: new FileSolutionFile(rootFile, rootFile),
823: actionOperation));
824: }
825:
826: public Document getSolutionTree(int actionOperation) {
827: return getSolutionTree(actionOperation, this );
828: }
829:
830: private void processSolutionTree(Element parentNode, File targetFile) {
831: if (targetFile.isDirectory()) {
832: if (!SolutionReposUtil
833: .ignoreDirectory(targetFile.getName())) {
834: Element childNode = parentNode.addElement(
835: ENTRY_NODE_NAME).addAttribute(TYPE_ATTR_NAME,
836: DIRECTORY_ATTR).addAttribute(NAME_ATTR_NAME,
837: targetFile.getName());
838: File files[] = targetFile.listFiles();
839: for (int i = 0; i < files.length; i++) {
840: File file = files[i];
841: processSolutionTree(childNode, file);
842: }
843: }
844: } else {
845: if (!targetFile.isHidden()
846: && !SolutionReposUtil.ignoreFile(targetFile
847: .getName())) {
848: parentNode.addElement(ENTRY_NODE_NAME).addAttribute(
849: TYPE_ATTR_NAME, FILE_ATTR).addAttribute(
850: NAME_ATTR_NAME, targetFile.getName());
851: }
852: }
853: }
854:
855: // -----------------------------------------------------------------------
856: // Methods from PentahoSystem
857: public boolean resourceExists(String solutionPath) {
858: String filePath = PentahoSystem.getApplicationContext()
859: .getSolutionPath(solutionPath);
860: File file = new File(filePath);
861: return file.exists();
862: }
863:
864: public long resourceSize(String solutionPath) {
865: if (!resourceExists(solutionPath)) {
866: return -1;
867: }
868: String filePath = PentahoSystem.getApplicationContext()
869: .getSolutionPath(solutionPath);
870: File file = new File(filePath);
871: return file.length();
872: }
873:
874: public String[] getAllActionSequences() {
875: File rootDir = getFile("", false); //$NON-NLS-1$
876: List files = new ArrayList();
877: files = getAllActionSequences(rootDir, files);
878: String[] value = new String[files.size()];
879: Iterator iter = files.iterator();
880: int i = 0;
881: int solutionPathOffset = PentahoSystem.getApplicationContext()
882: .getSolutionPath("").length(); //$NON-NLS-1$
883: while (iter.hasNext()) {
884: File file = (File) iter.next();
885: String filePath = file.getAbsolutePath();
886: filePath = filePath.substring(solutionPathOffset);
887: filePath = filePath.replace('\\', '/');
888: value[i++] = filePath;
889: }
890: return value;
891: }
892:
893: private List getAllActionSequences(File rootDir, List files) {
894: if (!rootDir.isDirectory()) {
895: return files;
896: }
897: File[] fileArray = rootDir.listFiles(new xActionFileFilter());
898: for (int i = 0; i < fileArray.length; i++) {
899: files.add(fileArray[i]);
900: }
901: fileArray = rootDir.listFiles();
902: for (int i = 0; i < fileArray.length; i++) {
903: if (fileArray[i].isDirectory()) {
904: getAllActionSequences(fileArray[i], files);
905: }
906: }
907: return files;
908: }
909:
910: public long getSolutionFileLastModified(String path) {
911: File file = getFile(path, false);
912: long mod = -1;
913: if (file != null) {
914: mod = file.lastModified();
915: }
916: return mod;
917: }
918:
919: class xActionFileFilter implements FilenameFilter {
920: public boolean accept(File dir, String name) {
921: int seperatorIndex = name.lastIndexOf('.');
922: if (seperatorIndex != -1) {
923: return name.substring(name.lastIndexOf('.'))
924: .equalsIgnoreCase(".xaction"); //$NON-NLS-1$
925: }
926: return false;
927: }
928: }
929:
930: public Document getNavigationUIDocument(String solution,
931: String path, int actionOperation) {
932: Document document = null;
933: if (StringUtils.isEmpty(solution)) {
934: document = this
935: .getSolutions(ISolutionRepository.ACTION_EXECUTE);
936: } else {
937: document = getActionSequences(solution, path, false, true,
938: ISolutionRepository.ACTION_EXECUTE);
939: }
940: return document;
941: }
942:
943: public boolean keepFile(ISolutionFile solutionFile,
944: int actionOperation) {
945: // No filtering of solution files/folders in the file-based repository
946: // yet.
947: return true;
948: }
949:
950: public String getRepositoryName() {
951: return "";//$NON-NLS-1$
952: }
953:
954: public boolean supportsACLS() {
955: return false;
956: }
957:
958: private String getRepositoryKey() {
959: return "repository" + getLocale().toString();//$NON-NLS-1$
960: }
961: }
|