001    /*
002     * file Utilities.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.Utilities
010     *
011     * (C) Copyright IBM Corporation 2004, 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    
016    package com.ibm.rational.stp.client.samples;
017    
018    import java.awt.Component;
019    import java.io.File;
020    import java.io.FileReader;
021    import java.lang.reflect.InvocationTargetException;
022    import java.util.List;
023    
024    import javax.swing.JOptionPane;
025    import javax.wvcm.Feedback;
026    import javax.wvcm.ProviderFactory;
027    import javax.wvcm.Resource;
028    import javax.wvcm.ResourceList;
029    import javax.wvcm.WvcmException;
030    import javax.wvcm.PropertyRequestItem.PropertyRequest;
031    import javax.wvcm.ProviderFactory.Callback;
032    import javax.wvcm.ProviderFactory.Callback.Authentication;
033    
034    import com.ibm.rational.wvcm.stp.StpException;
035    import com.ibm.rational.wvcm.stp.StpProvider;
036    import com.ibm.rational.wvcm.stp.StpResource;
037    import com.ibm.rational.wvcm.stp.StpProvider.Domain;
038    import com.ibm.rational.wvcm.stp.StpProvider.StpCallback;
039    import com.ibm.rational.wvcm.stp.cq.CqDbSet;
040    import com.ibm.rational.wvcm.stp.cq.CqProvider;
041    import com.ibm.rational.wvcm.stp.cq.CqUser;
042    import com.ibm.rational.wvcm.stp.cq.CqUserDb;
043    
044    /**
045     * A collection of static utility methods supporting the CM API examples
046     */
047    public class Utilities {
048    
049        /**
050         * A simple Authentication object in which the username and password
051         * obtained from the user is cached for use by the CM API.
052         */
053        static class UnPw implements Authentication {
054            /**
055             * Constructs an Authentication object
056             * 
057             * @param unpw A String[] containing the username and password.
058             */
059            UnPw(String[] unpw) {  m_data = unpw; }
060    
061            public String loginName() { return m_data[0]; }
062            public String password() { return m_data.length > 1 ? m_data[1] : ""; };
063    
064            /** The cached credentials */
065            private String[] m_data;
066        }
067    
068        /** Password used by static callback */
069        public static String g_pass = "";
070        /** User name used by static callback */
071        public static String g_user = "admin";
072    
073        private static Callback g_callback = new Callback()
074        {
075            public Authentication getAuthentication(String realm, int retryCount)
076            {
077                if (retryCount > 0)
078                    throw new IllegalAccessError("Wrong username/password for " + realm);
079                return new Authentication()
080                {
081                    public String loginName()
082                    {
083                        return g_user;
084                    }
085    
086                    public String password()
087                    {
088                        return g_pass;
089                    }
090                };
091            }
092        };
093    
094        public static CqProvider getStaticProvider()
095        throws Exception
096        {
097            return (CqProvider) ProviderFactory
098                .createProvider(CqProvider.CQ_ONLY_PROVIDER_CLASS, g_callback);        
099        }
100        
101        /**
102         * Constructs an instance of the CM API provider with or without an
103         * authenticator.
104         * 
105         * @return The instantiated Provider object
106         * @throws Exception
107         *             If the Provider could not be instantiated
108         */
109        static StpProvider getProvider() throws Exception {
110            try {
111                Callback callback = new StpCallback() {
112                    private UnPw m_unpw;
113        
114                    public Authentication getAuthentication(String r, int c)
115                    {   return null; /* Will not be called */   }
116        
117                    public Authentication getAuthenticationEx(Domain domain,
118                                                              String realm,
119                                                              int retryCount,
120                                                              StpProvider provider,
121                                                              WvcmException failure) 
122                    throws WvcmException
123                    {
124                        // Try to reuse last credentials on each new repository
125                        if (m_unpw != null && retryCount == 0)
126                            return m_unpw;
127        
128                        String title = "Enter " + domain 
129                                + " Username '+' Password for "
130                                + realm + " [" + retryCount + "]";
131                        
132                        if (failure != null)
133                            title = "Login failed: " + failure + "\n" + title;
134                        
135                        String unpw = JOptionPane.showInputDialog(title, "admin+");
136        
137                        if (unpw == null || unpw.length() == 0)
138                            throw new IllegalAccessError("User canceled request");
139                        
140                        if (unpw.equals("anonymous"))
141                            return null;
142                        
143                        if (unpw.startsWith("@")) {
144                            File file = new File(unpw.substring(1));
145        
146                            try {
147                                FileReader reader = new FileReader(file);
148                                char[] buf = new char[100];
149                                int count = reader.read(buf);
150        
151                                unpw = new String(buf, 0, count);
152                                reader.close();
153                            } catch (Throwable t) {
154                                Utilities.exception(null,
155                                                    "Reading password file " + unpw,
156                                                    t);
157                            }
158                        }
159        
160                        return m_unpw = new UnPw(unpw.split("\\+", -2));
161                    }
162                };
163        
164                // Instantiate a Provider
165                return (StpProvider) ProviderFactory
166                    .createProvider(StpProvider.PROVIDER_CLASS, callback);
167            } catch (InvocationTargetException ite) {
168                WvcmException e = (WvcmException) ite.getTargetException();
169        
170                System.out.println("*** " + e);
171                
172                for (Throwable nested: e.getNestedExceptions())
173                    System.out.println("***  " + nested);
174        
175                throw e;
176            }
177        }
178    
179        static ResourceList<CqUserDb> getUserDbList(CqProvider provider, 
180                                                    PropertyRequest feedback)
181        throws WvcmException
182        {
183            PropertyRequest wantedProps =
184                new PropertyRequest(CqDbSet.CURRENT_USER
185                    .nest(CqUser.SUBSCRIBED_DATABASES.nest(feedback)));
186            ResourceList<CqUserDb> result = provider.resourceList();
187    
188            for (CqDbSet set : provider.doGetDbSetList(wantedProps)) {
189                if (set.getResourceError() == null)
190                    result.addAll(set.getCurrentUser().getSubscribedDatabases());
191            }
192    
193            return result;
194        }
195        
196        /**
197         * Extracts the message content from a Throwable and returns it as a
198         * hierarchical array of Strings capturing the nesting of the Throwable's
199         * message components. This structure formats reasonably in a SWING
200         * showMessageDialog invocation.
201         * 
202         * @param ex The Throwable object whose message content is to be extracted.
203         * @return If the given Throwable has nested components, an array consisting
204         *         of the Throwable's message and an array of the nested messages.
205         */
206        private static Object messages(Throwable ex) {
207            String msg = ex.getLocalizedMessage();
208        
209            if (msg == null || msg.length() == 0)
210                msg = ex.toString();
211        
212            if (ex instanceof StpException) {
213                Throwable[] nested = ((StpException) ex).getNestedExceptions();
214        
215                if (nested != null && nested.length > 0) {
216                    Object[] msgs = new Object[nested.length];
217        
218                    for (int i = 0; i < msgs.length; ++i)
219                        msgs[i] = messages(nested[i]);
220        
221                    return new Object[] { msg, msgs };
222                }
223            } else if (ex.getCause() != null) {
224                return new Object[] {msg, new Object[]{messages(ex.getCause())}};
225            }
226        
227            return msg;
228        }
229        
230        /**
231         * Displays a Swing dialog containing the messages associated with a given
232         * Throwable.
233         * 
234         * @param frame The parent frame for the message dialog.
235         * @param title The title to appear in the dialog window.
236         * @param ex The throwable whose messages are to be displayed.
237         */
238        static void exception(Component frame, String title, Throwable ex) {
239            JOptionPane.showMessageDialog(frame,
240                                          messages(ex),
241                                          title,
242                                          JOptionPane.ERROR_MESSAGE);
243        }
244    
245        /**
246         * Returns a String suitable for displaying the type of resource as
247         * determined by its proxy class.
248         * 
249         * @param resource
250         *            A Resource proxy from which the type of resource will be
251         *            determined.
252         * @return A String containing the simple name of the most derived CM API 
253         * interface implemented by the given proxy.
254         */
255        static String resourceType(Resource resource) {
256            Class interfaces[] = resource.getClass().getInterfaces();
257            Class<?> choice = Resource.class;
258    
259            for (int i = 0; i < interfaces.length; ++i) {
260                String name = interfaces[i].getName();
261                if (name.startsWith("com.ibm.rational.wvcm.")
262                    || name.startsWith("javax.wvcm")) {
263    
264                    // Within the CM API, select the most derived interface
265                    // this resource implements
266                    if (choice.isAssignableFrom(interfaces[i]))
267                        choice = interfaces[i];
268                }
269            }
270    
271            String name = choice.getName();
272            
273            return name.substring(1+name.lastIndexOf('.'));
274        }
275        
276        static boolean isListOfResources(Object val)
277        {
278            return val instanceof ResourceList;
279        }
280        
281        static ResourceList<? extends StpResource> toResourceList(StpProvider provider, 
282                                                                  List list)
283        {
284            if (list instanceof ResourceList)
285                return (ResourceList<? extends StpResource>)list;
286            
287            return provider.resourceList();
288        }
289    }