001    /*
002     * file CcBrowser.java
003     *
004     * Licensed Materials - Property of IBM
005     * Restricted Materials of IBM - you are allowed to copy, modify and 
006     * redistribute this file as part of any program that interfaces with 
007     * IBM Rational CM API.
008     *
009     * com.ibm.rational.stp.client.samples.CcBrowser
010     *
011     * © Copyright IBM Corporation 2006, 2008.  All Rights Reserved
012     * Note to U.S. Government Users Restricted Rights:  Use, duplication or 
013     * disclosure restricted by GSA ADP  Schedule Contract with IBM Corp.
014     */
015    package com.ibm.rational.stp.client.samples;
016    
017    import java.awt.BorderLayout;
018    import java.awt.FlowLayout;
019    import java.awt.Font;
020    import java.awt.Label;
021    import java.awt.event.ActionEvent;
022    import java.awt.event.ActionListener;
023    import java.io.File;
024    import java.util.Arrays;
025    import java.util.Vector;
026    
027    import javax.swing.BoxLayout;
028    import javax.swing.JButton;
029    import javax.swing.JDialog;
030    import javax.swing.JFrame;
031    import javax.swing.JPanel;
032    import javax.swing.JScrollPane;
033    import javax.swing.JTextArea;
034    import javax.swing.JTextField;
035    import javax.swing.plaf.basic.BasicBorders;
036    import javax.wvcm.ControllableFolder;
037    import javax.wvcm.WvcmException;
038    
039    import com.ibm.rational.stp.client.samples.BrowserDataModel.Operations;
040    import com.ibm.rational.wvcm.stp.StpLocation;
041    import com.ibm.rational.wvcm.stp.StpProvider;
042    import com.ibm.rational.wvcm.stp.cc.CcActivity;
043    import com.ibm.rational.wvcm.stp.cc.CcConfigSpec;
044    import com.ibm.rational.wvcm.stp.cc.CcFile;
045    import com.ibm.rational.wvcm.stp.cc.CcProvider;
046    import com.ibm.rational.wvcm.stp.cc.CcResource;
047    import com.ibm.rational.wvcm.stp.cc.CcStream;
048    import com.ibm.rational.wvcm.stp.cc.CcView;
049    
050    /**
051     * An extension of the Browser example demonstrating application of ClearCase
052     * operations to the displayed resource
053     * 
054     */
055    public class CcBrowser implements Operations {
056    
057        public CcBrowser(com.ibm.rational.wvcm.stp.StpResource res) {
058            m_resource = res;
059        }
060    
061        /**
062         * Returns the operations supported by the type of ClearCase resource being
063         * displayed in this window.
064         * 
065         * @see com.ibm.rational.stp.client.samples.BrowserDataModel.Operations#getList()
066         */
067        public Vector<String> getList() {
068            if (m_resource instanceof CcView)
069                return new Vector<String>(Arrays.asList(viewOps));
070            else if (m_resource instanceof ControllableFolder)
071                return new Vector<String>(Arrays.asList(folderOps));
072            else if (m_resource instanceof CcFile)
073                return new Vector<String>(Arrays.asList(fileOps));
074            else
075                return new Vector<String>(Arrays.asList(otherOps));
076        }
077    
078        /**
079         * Supports the operations implemented in the 7.1 CM API
080         * <ul>
081         * <li>VOB properties
082         * <li>Get CQ CqUserDb from Project (Translate CLEARQUEST_USER_DB property
083         * from CqUserDbRef to CqUserDb (ref.getUserDb))
084         * <li>Create Stream(parent stream, is-read-only, is-integration-stream)
085         * <li>Create Activity(headline, comment)
086         * <li>Get CQ record for an activity (Translate MY_ACTIVITY_LIST to Record
087         * list via CqRecordRef.getRecord().)
088         * <li>Create a Web view(new directory name, new tag name) Delete a view
089         * </ul>
090         */
091        public void execute(Object op, BrowserDataModel model) {
092            try {
093                if (op.equals(EDITCS_OP)) {
094                    showConfigSpec((CcView) m_resource, true);
095                } else if (op.equals(VIEWCS_OP)) {
096                    showConfigSpec((CcView) m_resource, false);
097                    return; // No need to refresh
098                } else if (op.equals(DELETE_OP)) {
099                    m_resource.doUnbindAll(null);
100                } else if (op.equals(MKVIEW_OP)) {
101                    showResource("New View", mkView(m_resource));
102                    return;
103                } else if (op.equals(MKACT_OP)) {
104                    showResource("New Activity", mkActivity(m_resource));
105                    return;
106                } else if (op.equals(MKSTREAM_OP)) {
107                    showResource("New Stream", mkStream(m_resource));
108                    return;
109                } else {
110                    CcFile res = (CcFile) m_resource;
111    
112                    if (op.equals(CHECKOUT_OP)) {
113                        res.doCheckout(null, null);
114                    } else if (op.equals(CHECKIN_OP)) {
115                        res.doCheckin(null, null);
116                    } else if (op.equals(UNCHECKOUT_OP)) {
117                        res.doUncheckout(null);
118                    } else if (op.equals(CONTROL_OP)) {
119                        res.doVersionControl(null);
120                    } else if (op.equals(LOAD_OP)) {
121                        res.doLoad(null);
122                    } else if (op.equals(REFRESH_OP)) {
123                        res.doRefresh(null, null);
124                    } else if (op.equals(EDIT_OP)) {
125                        File file = ((StpLocation) res.location()).getFile();
126                        Runtime.getRuntime().exec("Notepad.exe \""
127                            + file.getCanonicalFile() + "\"");
128                        return; // no need to redisplay
129                    } else if (op.equals(MKFILE_OP)) {
130                        showResource("New File", mkFile(m_resource));
131                        return; // no need to redisplay
132                    } else if (op.equals(MKDIR_OP)) {
133                        showResource("New Directory", mkDir(m_resource));
134                        return; // no need to redisplay
135                    } else
136                        return;
137                }
138    
139                model.redisplay();
140            } catch (Throwable t) {
141                Utilities.exception(null, "Invalid resource", t);
142            }
143        }
144    
145        /**
146         * Displays the Config Spec for a specified ClearCase View and, optionally,
147         * allows the user to edit it.
148         * 
149         * @param view
150         *            The Workspace proxy for the ClearCase view whose ConfigSpec is
151         *            to be displayed. Must not be null and must define the
152         *            CONFIG_SPEC property.
153         * @param allowEdit
154         *            If true, the displayed Config Spec is made editable and a
155         *            button is added to the window for the user to click to commit
156         *            the modified Config Spec.
157         * @throws WvcmException
158         *             thrown if the required properties are not defined by the
159         *             given proxy.
160         */
161        private void showConfigSpec(final CcView view, boolean allowEdit)
162                        throws WvcmException {
163            final CcConfigSpec cs = view.getConfigSpec();
164            final JTextArea text = new JTextArea(680, 400);
165    
166            text.append(cs.getElementRules());
167            text.append(BAR);
168            text.append(cs.getLoadRules());
169            text.setBorder(BasicBorders.getTextFieldBorder());
170            text.setCaretPosition(0);
171            text.setFont(new Font("Monospaced", Font.PLAIN, 12));
172    
173            JFrame frame = new JFrame("Config Spec for " + view.getDisplayName());
174            final JDialog dialog = new JDialog(frame);
175            final JPanel panel = new JPanel(new BorderLayout());
176    
177            if (allowEdit) {
178                final JPanel subpanel = new JPanel(new FlowLayout());
179                JButton update = new JButton("Update");
180    
181                subpanel.add(update);
182                update.addActionListener(new ActionListener() {
183                    public void actionPerformed(ActionEvent arg0) {
184                        // set the return value here
185                        try {
186                            String newSpec = text.getText();
187                            int sep = newSpec.indexOf(BAR);
188    
189                            cs.setElementRules(newSpec.substring(0, sep));
190                            cs.setLoadRules(newSpec.substring(sep + BAR.length()));
191    
192                            view.setConfigSpec(cs);
193                            view.doWriteProperties(null);
194                            dialog.setVisible(false);
195                        } catch (Throwable t) {
196                            Utilities.exception(dialog, "Update Config Spec", t);
197                        }
198                    }
199                });
200    
201                panel.add(subpanel, BorderLayout.SOUTH);
202    
203                dialog.setModal(true);
204            }
205    
206            panel.add(new JScrollPane(text), BorderLayout.CENTER);
207    
208            dialog.setContentPane(panel);
209            dialog.setBounds(200, 300, 600, 300);
210            dialog.setVisible(true);
211            dialog.setVisible(false);
212        }
213    
214        /**
215         * A convenience method for invoking {@link Browser#showResource 
216         * Browser.showResource} on a given resource only if it is not null.
217         * 
218         * @param name A brief description of the resource type for inclusion in
219         * the title of window that will be used to display the resource
220         * @param res The resource to be displayed. May be null.
221         * @throws WvcmException If there are problems viewing a non-null resource.
222         */
223        void showResource(String name, CcResource res) throws WvcmException {
224            if (res != null) {
225                Browser.showResource(name + " " + res.location(),
226                                     res,
227                                     Browser.META_PROPS.toArray(),
228                                     true);
229            }
230        }
231    
232        /**
233         * Creates a new file after getting its name from the user. 
234         * @param dir The directory in which to create the new file.
235         * @return A ControllableResource proxy representing the newly created
236         * file.
237         */
238        CcFile mkFile(javax.wvcm.Resource dir) {
239            try {
240                String[] names = { "New File Location" };
241                // Todo Need to decode the selector name
242                String[] args = { ((StpLocation) dir.location()).getCanonicalPath() };
243    
244                getArgs(names, args);
245    
246                File file = new File(args[0]);
247                CcProvider provider = (CcProvider) dir.provider();
248                StpLocation fileLoc = provider
249                    .filePathLocation(StpProvider.Domain.CLEAR_CASE, file);
250    
251                file.createNewFile();
252                // TODO Need to modify this for running on UNIX systems
253                Runtime.getRuntime().exec("Notepad.exe \""
254                    + file.getCanonicalFile() + "\"");
255    
256                return provider.ccFile(fileLoc);
257            } catch (Throwable t) {
258                Utilities.exception(null, "Make File", t);
259            }
260    
261            return null;
262        }
263    
264        /**
265         * Creates a new directory after obtaining its name from the user
266         * @param parent The default context in which the directory will be 
267         * constructed. May be changed by user.
268         * @return A ControllableFolder for the newly constructed directory.
269         */
270        CcFile mkDir(javax.wvcm.Resource parent) {
271            try {
272                String[] names = { "New Directory Location" };
273                String[] args =
274                    { ((StpLocation) parent.location()).getCanonicalPath() };
275    
276                getArgs(names, args);
277    
278                File dir = new File(args[0]);
279                CcProvider provider = (CcProvider) parent.provider();
280                StpLocation fileLoc = provider
281                    .filePathLocation(StpProvider.Domain.CLEAR_CASE, dir);
282    
283                dir.mkdir();
284    
285                return provider.ccDirectory(fileLoc);
286            } catch (Throwable t) {
287                Utilities.exception(null, "Make Directory", t);
288            }
289    
290            return null;
291        }
292    
293        /**
294         * Creates a ClearCase view after getting creation parameters from the user.
295         * @param context The Default context in which the view is to be created.
296         * May be modified by the user.
297         * @return A Workspace proxy for the created view. Will be null if the
298         * view was not created.
299         */
300        CcView mkView(javax.wvcm.Resource context) {
301            try {
302                String[] names = { "View Tag", "File Area", "Comment" };
303                String[] args = { null, context.location().string(), "Create view" };
304    
305                getArgs(names, args);
306    
307                CcProvider provider = (CcProvider) context.provider();
308                StpLocation clientLoc = (StpLocation) provider.location(args[1]);
309                CcView clientWs = provider.ccView(clientLoc);
310    
311                clientWs.setComment(args[2]);
312                // TODO When implemented...
313                // clientWs.setIsUcmView(args[3]);
314                //
315                // if (clientWs.getIsUcmView()) {
316                // clientWs.setProject(args[4]);
317                // clientWs.setStream(args[5]);
318                // }
319                clientWs.doCreateResource(null);
320            } catch (Throwable t) {
321                Utilities.exception(null, "Make View", t);
322            }
323            
324            return null;
325        }
326    
327        /**
328         * Creates a new UCM Stream after obtaining parameters from user.
329         * @param context The default context in which to create the new UCM Stream.
330         * May be modified by the user.
331         * @return A UcmStream proxy for the new stream; null if the stream was not
332         * created.
333         */
334        CcStream mkStream(javax.wvcm.Resource context) {
335            try {
336                String[] args = getArgs(new String[] { "Name (required)",
337                    "Parent Stream/Project (required)",
338                    "Is Read Only (true/false)",
339                    "Default Deliver Target (optional)" });
340                CcProvider provider = (CcProvider) context.provider();
341                StpLocation streamLoc = (StpLocation) provider.location(args[0]);
342                CcStream stream = provider.ccStream(streamLoc);
343                StpLocation parentSelector = provider.stpLocation(args[1]);
344    
345                if (parentSelector.getNamespace().equals(StpLocation.Namespace.STREAM)) {
346                    stream.setIsIntegrationStream(false);
347                    stream.setParentStream(provider.ccStream((StpLocation) provider
348                        .location(args[1])));
349                } else {
350                    stream.setIsIntegrationStream(true);
351                    stream.setParentProject(provider.ccProject((StpLocation) provider
352                        .location(args[1])));
353                }
354    
355                stream.setIsReadOnly(args[2].startsWith("t"));
356    
357                if (args[3].length() > 0) {
358                    stream.setDefaultDeliverTarget(provider
359                        .ccStream((StpLocation) provider.location(args[3])));
360                }
361    
362                stream.doCreateResource(null);
363    
364                return stream;
365            } catch (Throwable t) {
366                Utilities.exception(null, "Make Stream", t);
367            }
368            return null;
369        }
370    
371        /**
372         * Creates an activity based on input from the user.
373         * @param context The context in which the activity will be created, which
374         * may be ignored by the user.
375         * @return A UcmActivity proxy for the newly created activity; null if the
376         * activity was not created.
377         */
378        CcActivity mkActivity(javax.wvcm.Resource context) {
379            try {
380                String[] args = getArgs(new String[] { "Stream (required)",
381                    "Headline (optional)", "Comment (optional)" });
382                CcProvider provider = (CcProvider) context.provider();
383                StpLocation streamLoc = (StpLocation) provider.location(args[0]);
384                CcStream stream = provider.ccStream(streamLoc);
385                StpLocation actloc = (StpLocation) provider.location("cc.activity:foo@"
386                    + streamLoc.getRepo());
387                CcActivity act = provider.ccActivity(actloc);
388    
389                act.setStream(stream);
390                act.setHeadline(args[1]);
391                act.setComment(args[2]);
392                act.doCreateResource(null);
393    
394                return act;
395            } catch (Throwable t) {
396                Utilities.exception(null, "Make Activity", t);
397            }
398    
399            return null;
400        }
401    
402        /**
403         * Displays a list of parameters to the user with default values and then
404         * allows the user to add or modify values.
405         * @param names The names of the parameters to be obtained from the user.
406         * @param result On input, the default values to display in the dialog;
407         * on output, contains the values entered by the user.
408         */
409        void getArgs(final String[] names, final String[] result) {
410            JFrame frame = new JFrame("Enter Parameters");
411            final JDialog dialog = new JDialog(frame);
412            final JPanel panel = new JPanel();
413            panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
414            final JTextField[] fields = new JTextField[names.length];
415    
416            for (int i = 0; i < names.length; ++i) {
417                JTextField field = new JTextField();
418    
419                if (result[i] != null)
420                    field.setText(result[i]);
421    
422                fields[i] = field;
423                panel.add(new Label(names[i]));
424                panel.add(field);
425            }
426    
427            JButton update = new JButton("Ok");
428    
429            panel.add(update);
430            update.addActionListener(new ActionListener() {
431                public void actionPerformed(ActionEvent arg0) {
432                    // set the return value here
433                    try {
434                        for (int j = 0; j < names.length; ++j)
435                            result[j] = fields[j].getText();
436    
437                        dialog.dispose();
438                    } catch (Throwable t) {
439                        Utilities.exception(dialog, "Specify Parameters", t);
440                    }
441                }
442            });
443    
444            dialog.setModal(true);
445            dialog.setContentPane(panel);
446            dialog.setBounds(200, 300, 600, 20 + 60 * names.length);
447            dialog.setVisible(false);
448        }
449    
450        /**
451         * Obtains a list of parameter values from the user.
452         * @param names The names of the parameters that user is supposed to provide.
453         * @return A String array contain the user's input for each parameter.
454         */
455        String[] getArgs(String[] names) {
456            final String[] result = new String[names.length];
457            getArgs(names, result);
458    
459            return result;
460        }
461    
462        /** 
463         * The line of text used to separate the Element Rules from the Load Rules
464         * in a Config Spec.
465         */
466        private static final String BAR = "=== Element Rules/Load Rules Boundary DO NOT REMOVE ===\n";
467    
468        final private static String CHECKOUT_OP = "Check Out";
469    
470        final private static String CHECKIN_OP = "Check In";
471    
472        final private static String UNCHECKOUT_OP = "Uncheck Out";
473    
474        final private static String CONTROL_OP = "Control";
475    
476        final private static String REFRESH_OP = "Refresh";
477    
478        final private static String LOAD_OP = "Load";
479    
480        // final private static String UNLOAD_OP = "Unload";
481        final private static String EDIT_OP = "Edit";
482    
483        final private static String DELETE_OP = "Delete";
484    
485        final private static String VIEWCS_OP = "View Config Spec";
486    
487        final private static String EDITCS_OP = "Edit Config Spec";
488    
489        final private static String MKDIR_OP = "Make Directory";
490    
491        final private static String MKFILE_OP = "Make File";
492    
493        final private static String MKVIEW_OP = "Make View";
494    
495        final private static String MKACT_OP = "Make Activity";
496    
497        final private static String MKSTREAM_OP = "Make Stream";
498    
499        /** The operations supported on Folders */
500        private static final String[] folderOps = { CHECKOUT_OP, CHECKIN_OP,
501            UNCHECKOUT_OP, CONTROL_OP, REFRESH_OP, LOAD_OP,
502            // UNLOAD_OP,
503            DELETE_OP, MKDIR_OP, MKFILE_OP, MKACT_OP, MKSTREAM_OP, MKVIEW_OP };
504    
505        /** The operations supported on Files */
506        private static final String[] fileOps = { CHECKOUT_OP, CHECKIN_OP,
507            UNCHECKOUT_OP, CONTROL_OP, REFRESH_OP, LOAD_OP,
508            // UNLOAD_OP,
509            EDIT_OP, DELETE_OP, MKACT_OP, MKSTREAM_OP, MKVIEW_OP };
510    
511        /** The operations supported on views */
512        private static final String[] viewOps = { VIEWCS_OP, EDITCS_OP, REFRESH_OP,
513            DELETE_OP, MKDIR_OP, MKACT_OP, MKSTREAM_OP, MKVIEW_OP, };
514    
515        /** The operations supported on all resources */
516        private static final String[] otherOps = { DELETE_OP, MKACT_OP,
517            MKSTREAM_OP, MKVIEW_OP, };
518    
519        /** A proxy for the resource being displayed by this Browser window */
520        com.ibm.rational.wvcm.stp.StpResource m_resource;
521    
522        /**
523         * Starts the ClearCase version of the Browser using the CcBrower class as
524         * the source for resource operations.
525         * 
526         * @param args
527         *            Not used in this application
528         */
529        public static void main(String[] args) throws Exception {
530            Browser.g_operationsClass = CcBrowser.class;
531    
532            Browser.main(args);
533        }
534    
535    }