001: package com.ice.jcvsweb.bean;
002:
003: import java.io.File;
004: import java.io.FileWriter;
005: import java.io.IOException;
006: import java.io.PrintWriter;
007: import java.util.ArrayList;
008: import java.util.Map;
009: import java.util.HashMap;
010:
011: import javax.servlet.ServletContext;
012:
013: import org.w3c.dom.Document;
014: import org.w3c.dom.DocumentType;
015: import org.w3c.dom.Element;
016: import org.w3c.dom.Node;
017: import org.w3c.dom.NodeList;
018: import org.w3c.dom.Text;
019: import org.xml.sax.Attributes;
020: import org.xml.sax.SAXException;
021:
022: import com.ice.cvsc.CVSClient;
023: import com.ice.cvsc.CVSCUtilities;
024: import com.ice.cvsc.CVSEntry;
025: import com.ice.cvsc.CVSProject;
026: import com.ice.cvsc.CVSRequest;
027: import com.ice.cvsc.CVSScramble;
028: import com.ice.cvsc.CVSTracer;
029: import com.ice.cvsc.CVSCUtilities;
030:
031: import com.ice.jcvsweb.helper.ContextHelper;
032: import com.ice.jcvsweb.helper.XMLHelper;
033:
034: /**
035: *
036: * @author Tim Endres, <a href="mailto:time@jcvs.org">time@jcvs.org</a>
037: * @see com.ice.cvsc
038: */
039:
040: public class JCVSProjectView {
041: public static final int PS_INIT = 0;
042: public static final int PS_LOAD = 10;
043: public static final int PS_CHKOUT = 20;
044: public static final int PS_CHKOUT_SCHED = 25;
045: public static final int PS_READY = 80;
046: public static final int PS_BROKEN = 99;
047:
048: /**
049: * The unique key of this view.
050: */
051: private String key = null;
052:
053: /**
054: * The view (or release tag) of the checked out project.
055: */
056: private String tag = null;
057:
058: /**
059: * The display name of this project.
060: */
061: private String name = null;
062:
063: /**
064: * A short title for this project.
065: */
066: private String title = null;
067:
068: /**
069: * The long and detailed description of this project definition.
070: */
071: private String desc = null;
072:
073: /**
074: * The module name passed to the checkout command.
075: */
076: private String module = null;
077:
078: /**
079: * If this String is not null, will be provided with "-d" option
080: * during checkout.
081: */
082: private String coDir = null;
083:
084: /**
085: * If this String is not null, it is the "default entry path" for
086: * "quick jump" links.
087: */
088: private String jump = null;
089:
090: private int state = PS_INIT;
091:
092: private JCVSProject project = null;
093:
094: private HashMap entryCache = null;
095: private CVSClient cvsClient = null;
096: private CVSProject cvsProject = null;
097:
098: private Object cvsLock = null;
099: private boolean cvsBusy = false;
100: private String reason = null;
101:
102: public JCVSProjectView() {
103: this .state = PS_INIT;
104: this .entryCache = new HashMap();
105: }
106:
107: public String getKey() {
108: return this .key;
109: }
110:
111: public void setKey(String key) {
112: this .key = key;
113: }
114:
115: public JCVSProject getProject() {
116: return this .project;
117: }
118:
119: public void setProject(JCVSProject project) {
120: this .project = project;
121: }
122:
123: public String getJump() {
124: return this .jump;
125: }
126:
127: public void setJump(String jump) {
128: this .jump = jump;
129: }
130:
131: public int getState() {
132: return this .state;
133: }
134:
135: // UNDONE
136: // Shouldn't the state be "synchronized" access?!?!
137: public void setState(int state) {
138: this .state = state;
139: }
140:
141: public String getStateName() {
142: if (this .state == PS_INIT)
143: return "Initializing";
144: if (this .state == PS_LOAD)
145: return "Loading";
146: if (this .state == PS_CHKOUT)
147: return "CheckOut";
148: if (this .state == PS_READY)
149: return "Ready";
150: if (this .state == PS_BROKEN)
151: return "Not Ready";
152: if (this .state == PS_CHKOUT_SCHED)
153: return "CheckOut Scheduled";
154: return "UNKNOWN";
155: }
156:
157: public boolean isBroken() {
158: return (this .state == PS_BROKEN);
159: }
160:
161: public boolean isReady() {
162: return (this .state == PS_READY);
163: }
164:
165: public String getReason() {
166: return this .reason;
167: }
168:
169: public void setReason(String reason) {
170: this .reason = reason;
171: }
172:
173: public synchronized boolean getCVSLock() {
174: boolean result = false;
175:
176: try {
177: while (this .cvsBusy)
178: this .wait();
179: } catch (InterruptedException ex) {
180: // UNDONE log( "getCVSLock()", ex );
181: }
182:
183: if (!this .cvsBusy) {
184: // Got it!
185: result = true;
186: this .cvsBusy = true;
187: }
188:
189: return result;
190: }
191:
192: public synchronized void releaseCVSLock() {
193: this .cvsBusy = false;
194: this .notifyAll();
195: }
196:
197: public CVSProject getCvsProject() {
198: return this .cvsProject;
199: }
200:
201: public void setCvsProject(CVSProject cvsProject) {
202: this .cvsProject = cvsProject;
203: }
204:
205: public String getCvsTag() {
206: return this .tag;
207: }
208:
209: public void setCvsTag(String tag) {
210: this .tag = tag;
211: }
212:
213: public String getViewName() {
214: return (this .project != null ? this .project.getDef().getKey()
215: : "NULL")
216: + "/" + this .key;
217: }
218:
219: public String getName() {
220: return this .name;
221: }
222:
223: public void setName(String name) {
224: this .name = name;
225: }
226:
227: public String getTitle() {
228: return this .title;
229: }
230:
231: public void setTitle(String title) {
232: this .title = title;
233: }
234:
235: public String getDescription() {
236: return this .desc;
237: }
238:
239: public void setDescription(String desc) {
240: this .desc = desc;
241: }
242:
243: public String getCvsModule() {
244: return this .module;
245: }
246:
247: public void setCvsModule(String module) {
248: this .module = module;
249: }
250:
251: public String getCodir() {
252: return this .coDir;
253: }
254:
255: public void setCodir(String coDir) {
256: this .coDir = coDir;
257: }
258:
259: public String getLogDirectory() {
260: String localDir = this .project.getDef().getLocalDirectory();
261: return CVSCUtilities.stripFinalSeparator(localDir)
262: + File.separator + "logs" + File.separator + this .key;
263: }
264:
265: public String getViewDirectory() {
266: String localDir = this .project.getDef().getLocalDirectory();
267: return CVSCUtilities.stripFinalSeparator(localDir)
268: + File.separator + "views" + File.separator + this .key;
269: }
270:
271: public String toString() {
272: StringBuffer sBuf = new StringBuffer(256);
273:
274: sBuf.append("[ ");
275: sBuf.append("key=").append(this .key).append(", ");
276: sBuf.append("tag=").append(this .tag).append(", ");
277: sBuf.append("prjkey=").append(this .project.getDef().getKey())
278: .append(", ");
279: sBuf.append("name=").append(this .name).append(", ");
280: sBuf.append("module=").append(this .module).append(", ");
281: sBuf.append("jump=").append(this .jump).append(", ");
282: sBuf.append("codir=").append(this .coDir).append(", ");
283: sBuf.append("title=").append(this .title).append(", ");
284: sBuf.append("state=").append(this .state).append(", ");
285: sBuf.append("reason='").append(this .reason).append("', ");
286: sBuf.append("cvsbusy=").append(this .cvsBusy).append(", ");
287: sBuf.append("entryCacheSize=").append(this .entryCache.size());
288: sBuf.append(" ]");
289:
290: return sBuf.toString();
291: }
292:
293: public void ensureViewIsOpen(ServletContext ctx) throws IOException {
294: JCVSProjectDef def = this .project.getDef();
295:
296: // System.err.println( "JCVSView.ensureViewIsOpen( "
297: // + this.getViewName() + " ) Directory '"
298: // + this.getViewDirectory() + "'" );
299:
300: // UNDONE HIGH
301: // GET THE LOCK!!! (?)
302: //
303: int curstate = this .getState();
304:
305: if (curstate == PS_INIT || curstate == PS_BROKEN) {
306: this .setState(PS_LOAD);
307: this .entryCache.clear();
308:
309: try {
310: String viewDir = ContextHelper.getRealAbsolutePath(ctx,
311: this .getViewDirectory());
312: // System.err.println( "VIEWDIR: '" + viewDir + "'" );
313:
314: String path = CVSProject
315: .rootPathToAdminPath(CVSCUtilities
316: .importPath(viewDir));
317: // System.err.println( "VIEWPATH: '" + path + "'" );
318:
319: if (!CVSProject.verifyAdminDirectory(path)) {
320: this .setState(PS_BROKEN);
321: this
322: .setReason("The project needs to be checked out.");
323: } else {
324: this .cvsClient = new CVSClient();
325: this .cvsProject = new CVSProject(this .cvsClient);
326: this .cvsProject.setAllowsGzipFileMode(false);
327:
328: String tempDir = def.getTempDirectory();
329: String tempDirPath = ContextHelper
330: .getRealAbsolutePath(ctx, tempDir);
331: this .cvsProject.setTempDirectory(tempDirPath);
332:
333: File rootDirFile = new File(viewDir);
334:
335: this .cvsProject.openProject(rootDirFile);
336:
337: int connMethod = this .cvsProject
338: .getConnectionMethod();
339:
340: this .cvsProject.setConnectionPort(def.getCvsPort());
341:
342: String passwd = (connMethod != CVSRequest.METHOD_INETD ? def
343: .getCvsPassword()
344: : CVSScramble.scramblePassword(def
345: .getCvsPassword(), 'A'));
346:
347: this .cvsProject.setPassword(passwd);
348:
349: this .setState(PS_READY);
350: this .setReason("Project is open and ready.");
351: }
352: } catch (IOException ex) {
353: this .setState(PS_BROKEN);
354: this .setReason(ex.getMessage());
355: ex.printStackTrace(System.err);
356: }
357:
358: Runtime rt = Runtime.getRuntime();
359: System.err.println("[MEM] Free " + rt.freeMemory()
360: + " Total " + rt.totalMemory());
361: }
362: }
363:
364: public JCVSEntry getRootEntry() {
365: CVSEntry entry = this .cvsProject.getRootEntry();
366:
367: JCVSEntry result = (JCVSEntry) this .entryCache.get(entry);
368:
369: if (result == null) {
370: result = new JCVSEntry();
371: result.setProjectView(this );
372: result.setCvsEntry(entry);
373: this .entryCache.put(entry, result);
374: }
375:
376: return result;
377: }
378:
379: public void clearEntryCache() {
380: this .entryCache.clear();
381: }
382:
383: public JCVSEntry getPackageEntry(String pkgName) {
384: if (false)
385: System.err.println("getPackageEntry() pkgName = '"
386: + pkgName + "'");
387:
388: if (this .getState() != PS_READY || this .project == null) {
389: // UNDONE
390: // REVIEW
391: System.err.println("getPackageEntry( " + pkgName
392: + " ), Not ready.");
393: return null;
394: }
395:
396: CVSEntry entry = this .cvsProject.getRootEntry();
397:
398: if (entry == null) {
399: // UNDONE
400: // REVIEW
401: System.err.println("getPackageEntry( " + pkgName
402: + " ), Root entry null.");
403: return null;
404: }
405:
406: String path = pkgName;
407:
408: if (!pkgName.equals("")) {
409: for (boolean done = false; !done;) {
410: String name;
411: int idx = path.indexOf("/");
412:
413: if (idx == -1) {
414: name = path;
415: done = true;
416: } else {
417: name = path.substring(0, idx);
418: path = path.substring(idx + 1);
419: }
420:
421: if (false)
422: System.err.println("getPackageEntry() find '"
423: + name + "' under " + entry);
424:
425: entry = entry.locateEntry(name);
426: if (entry == null) {
427: done = true;
428: if (false)
429: System.err.println("getPackageEntry() find '"
430: + name + "' returns null.");
431: }
432: }
433: }
434:
435: JCVSEntry result = null;
436: if (entry != null) {
437: result = (JCVSEntry) this .entryCache.get(entry);
438:
439: if (result == null) {
440: result = new JCVSEntry();
441: result.setProjectView(this );
442: result.setCvsEntry(entry);
443: this .entryCache.put(entry, result);
444: }
445: }
446:
447: return result;
448: }
449:
450: public ArrayList establishPathBar(String pkgName) {
451: ArrayList result = new ArrayList();
452:
453: if (false)
454: System.err.println("establishPathBar() pkgName = '"
455: + pkgName + "'");
456:
457: if (this .getState() != PS_READY || this .project == null) {
458: // UNDONE
459: // REVIEW
460: System.err.println("establishPathBar( " + pkgName
461: + " ), Not ready.");
462: return null;
463: }
464:
465: CVSEntry entry = this .cvsProject.getRootEntry();
466:
467: if (entry == null) {
468: // UNDONE
469: // REVIEW
470: System.err.println("establishPathBar( " + pkgName
471: + " ), Root entry null.");
472: return null;
473: }
474:
475: String path = pkgName;
476:
477: if (!pkgName.equals("")) {
478: String subPath = "";
479: for (boolean done = false; !done;) {
480: String name;
481: int idx = path.indexOf("/");
482:
483: if (idx == -1) {
484: name = path;
485: done = true;
486: } else {
487: name = path.substring(0, idx);
488: path = path.substring(idx + 1);
489: }
490:
491: if (false)
492: System.err.println("establishPathBar() find '"
493: + name + "' under " + entry);
494:
495: entry = entry.locateEntry(name);
496: if (entry == null) {
497: done = true;
498: System.err.println("establishPathBar() find '"
499: + name + "' returns null.");
500: } else {
501: subPath = subPath
502: + (subPath.length() > 0 ? "/" : "") + name;
503:
504: boolean isDir = entry.isDirectory();
505: String[] sa = { name, (isDir ? "list" : "vers"),
506: (isDir ? "pathbardir" : "pathbarfile"),
507: subPath };
508:
509: if (false)
510: System.err.println("establishPathBar() ITEM '"
511: + sa[0] + "', '" + sa[1] + "', '"
512: + sa[2] + "', '" + sa[3] + "'");
513:
514: result.add(sa);
515: }
516: }
517: }
518:
519: return result;
520: }
521:
522: public void loadConfiguration(Node viewNode) throws SAXException {
523: NodeList children = viewNode.getChildNodes();
524: for (int ni = 0; ni < children.getLength(); ++ni) {
525: Node child = children.item(ni);
526: if (child != null
527: && child.getNodeType() == Node.ELEMENT_NODE) {
528: String name = child.getNodeName();
529: String value = XMLHelper
530: .getElementValue((Element) child);
531:
532: if ("key".equals(name)) {
533: this .setKey(value);
534: } else if ("name".equals(name)) {
535: this .setName(value);
536: } else if ("cvstag".equals(name)) {
537: this .setCvsTag(value);
538: } else if ("desc".equals(name)) {
539: this .setDescription(value);
540: } else if ("module".equals(name)) {
541: this .setCvsModule(value);
542: } else if ("jump".equals(name)) {
543: this .setJump(value);
544: } else if ("title".equals(name)) {
545: this .setTitle(value);
546: }
547: } else {
548: if (child.getNodeType() != Node.TEXT_NODE)
549: System.err.println("SKIP node type"
550: + " ["
551: + child.getNodeType()
552: + "] '"
553: + XMLHelper.getNodeTypeName(child
554: .getNodeType()) + "' name = '"
555: + child.getNodeName() + "'");
556: }
557: }
558:
559: // UNDONE HIGH
560: // if ( ! this.validate() )
561: // {
562: // Validate the localdir, cvsroot, etc...
563: // }
564: }
565:
566: public void saveConfiguration(PrintWriter pW, String prefix) {
567: pW.print(prefix);
568: pW.println("<jcvs-view>");
569: pW.println("");
570:
571: pW.print(prefix);
572: pW.print(" <key>");
573: pW.print(this .key);
574: pW.println("</key>");
575:
576: pW.print(prefix);
577: pW.print(" <name>");
578: pW.print(this .name);
579: pW.println("</name>");
580:
581: pW.print(prefix);
582: pW.print(" <title>");
583: pW.print(this .title);
584: pW.println("</title>");
585:
586: pW.print(prefix);
587: pW.print(" <cvstag>");
588: pW.print(this .tag);
589: pW.println("</cvstag>");
590:
591: pW.print(prefix);
592: pW.print(" <module>");
593: pW.print(this .module);
594: pW.println("</module>");
595:
596: pW.print(prefix);
597: pW.print(" <jump>");
598: pW.print(this .jump);
599: pW.println("</jump>");
600:
601: pW.print(prefix);
602: pW.print(" <desc>");
603: pW.print(this .desc);
604: pW.println("</desc>");
605:
606: pW.println("");
607: pW.print(prefix);
608: pW.println("</jcvs-view>");
609: }
610:
611: }
|