Coverage Report - org.apache.commons.jjar.DependencyEngine
 
Classes in this File Line Coverage Branch Coverage Complexity
DependencyEngine
0%
0/96
0%
0/42
2.368
Node
0%
0/22
N/A
2.368
 
 1  
 /*
 2  
  * Copyright 2001,2004 The Apache Software Foundation.
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.apache.commons.jjar;
 18  
 
 19  
 import java.util.HashMap;
 20  
 import java.util.List;
 21  
 import java.util.Iterator;
 22  
 import java.util.ArrayList;
 23  
 import java.lang.Thread;
 24  
 
 25  
 /**
 26  
  *  <p>
 27  
  *  Simple class to figure out ordered dependency lists.  Basic
 28  
  *  idea is that you load it with datum consisting of a set 
 29  
  *  consisting of  a package name and list of packages that 
 30  
  *  it's dependent upon.
 31  
  *  </p>
 32  
  *
 33  
  *  <p>
 34  
  *  Then, you should be able to ask for the dependencies for any
 35  
  *  package placed in there.
 36  
  *  </p>
 37  
  *
 38  
  *  <p> will detect loops at 'runtime', not loadtime.  Just punts
 39  
  *  when that happens
 40  
  *  </p>
 41  
  *
 42  
  *  <p>
 43  
  *  This thing isn't close to threadsafe :)
 44  
  *  </p>
 45  
  *
 46  
  *  @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
 47  
  *  @version $Id: DependencyEngine.java 155454 2005-02-26 13:23:34Z dirkv $ 
 48  
  */
 49  
 public class DependencyEngine
 50  
 {    
 51  0
     private HashMap projects = new HashMap();
 52  0
     private ArrayList buildList = null;
 53  
 
 54  
     /**
 55  
      *  this is a real sucky solution to something I don't want to 
 56  
      *  think about right now...  we use this to ensure that
 57  
      *  the information in our graph is fresh
 58  
      */
 59  0
     private long currentTimestamp = -1;
 60  
     
 61  
     /**
 62  
      *  CTOR 
 63  
      */
 64  
     public DependencyEngine()
 65  0
     {
 66  0
     }
 67  
 
 68  
     /**
 69  
      * Reset the dependency engine, clear all entries
 70  
      * and start from scratch.
 71  
      */
 72  
     public void reset()
 73  
     {
 74  0
         projects = new HashMap();
 75  0
     }        
 76  
 
 77  
     /**
 78  
      *  returns a list of dependencies for a given package
 79  
      *  with the target being excluded from the list.
 80  
      *
 81  
      *  @param pkg package to get dependency list for
 82  
      *  @return List list of dependencies, in order
 83  
      */
 84  
     public List getDependencies( String pkg )
 85  
     {
 86  0
         return getDependencies(pkg, true);
 87  
     }        
 88  
 
 89  
     /**
 90  
      *  returns a list of dependencies for a given package
 91  
      *  allowing the exclusion/inclusion of the target package.
 92  
      *
 93  
      *  @param pkg package to get dependency list for
 94  
      *  @param excludeTarget boolean to control exclusion of target package
 95  
      *  @return List list of dependencies, in order
 96  
      */
 97  
     public List getDependencies( String pkg, boolean excludeTarget )
 98  
     {
 99  0
         buildList = new ArrayList();
 100  
 
 101  
         try
 102  
         {
 103  
             /*
 104  
              *  if we are called in the same millisecond as our 
 105  
              *  last trip through, sleep as the sucky 'fresh graph'
 106  
              *  solution depends on this, and this would be quite
 107  
              *  an interesting time-dependent thing to debug :)
 108  
              */
 109  0
             if (System.currentTimeMillis() == currentTimestamp)
 110  
             {
 111  0
                 Thread.sleep(1);
 112  
             }
 113  
 
 114  
             /*
 115  
              *  set the current time so we can see if our graph node
 116  
              *  state is for this trip, or a previous trip.
 117  
              */
 118  0
             currentTimestamp = System.currentTimeMillis();
 119  
 
 120  
             /*
 121  
              *  now, just do it
 122  
              */
 123  0
             doIt( pkg );
 124  
         }
 125  0
         catch( Exception e )
 126  
         {
 127  0
             System.out.println("DE.getDependencies() : " + pkg + " : "  + e);
 128  0
         }
 129  
         
 130  
         // The the multi project dep list this code is lopping
 131  
         // off the package stated as the target. Need a flag to
 132  
         // indicated whether you want the target included or
 133  
         // or. For a multi-project build like maven you need
 134  
         // the target because you actually want to build the
 135  
         // target. For the JJAR task you don't want the target
 136  
         // because you're just downloading JARs.
 137  0
         if( excludeTarget && buildList.size() > 0)
 138  
         {
 139  0
             buildList.remove( buildList.size() - 1 );
 140  
         }
 141  
 
 142  0
         return buildList;
 143  
     }
 144  
 
 145  
     /**
 146  
      *  Generates a dependency list for a set of packages.
 147  
      *
 148  
      *  @param packages List of strings, each string is a package name
 149  
      *  @return list of dependencies, in order
 150  
      */
 151  
     public List getDependencies(List packages)
 152  
     {
 153  0
         return getDependencies(packages, true);
 154  
     }
 155  
 
 156  
     /**
 157  
      *  Generates a dependency list for a set of packages
 158  
      *  where there is the option to exclude/include the
 159  
      *  target packages.
 160  
      *
 161  
      *  @param packages List of strings, each string is a package name
 162  
      *  @param excludeTarget boolean to exclude target
 163  
      *  @return List list of dependencies, in order
 164  
      */
 165  
     public List getDependencies( List packages, boolean excludeTarget )
 166  
     {
 167  0
         HashMap h = new HashMap();
 168  0
         ArrayList l = new ArrayList();
 169  
 
 170  
         /*
 171  
          *  for each package, get the dependency list
 172  
          *  and drop them into the list if it's not already 
 173  
          *  in there
 174  
          */
 175  
         
 176  0
         for( Iterator i = packages.iterator(); i.hasNext(); )
 177  
         {
 178  0
             String pkg = (String) i.next();
 179  
 
 180  0
             List deps = getDependencies( pkg, excludeTarget );
 181  
 
 182  0
             for (Iterator ii = deps.iterator(); ii.hasNext(); )
 183  
             {
 184  0
                 String dep = (String) ii.next();
 185  
 
 186  0
                 if ( h.get( dep ) == null)
 187  
                 {
 188  0
                     h.put(dep, dep);
 189  0
                     l.add(dep);
 190  
                 }
 191  0
             }
 192  0
         }
 193  
 
 194  0
         return l;
 195  
     }
 196  
 
 197  
 
 198  
     /**
 199  
      *  from previous use - generates a dependency list
 200  
      *  spanning the entire tree.  Returns a list
 201  
      *  of names.
 202  
      */
 203  
     public List generateNamelist()
 204  
         throws Exception
 205  
     {
 206  
         /*
 207  
          *  get the project list
 208  
          */
 209  
 
 210  0
         buildList = new ArrayList();
 211  
 
 212  0
         Iterator i = projects.keySet().iterator();
 213  
 
 214  0
         while(i.hasNext())
 215  
         {
 216  0
             String s = (String) i.next();
 217  
 
 218  
             /*
 219  
              *  make them by name
 220  
              */
 221  
 
 222  0
             doIt( s );
 223  0
         }
 224  
 
 225  0
         return buildList;
 226  
     }
 227  
 
 228  
     /**
 229  
      *  from previous use - generates a dependency list
 230  
      *  spanning the entire tree.  Returns a list
 231  
      *  of cookies.
 232  
      */
 233  
     public List generateCookielist()
 234  
         throws Exception
 235  
     {
 236  
         /*
 237  
          *  get the project list
 238  
          */
 239  
 
 240  0
         List list = generateNamelist();
 241  0
         ArrayList cookies = new ArrayList();
 242  
 
 243  0
         Iterator i = list.iterator();
 244  
 
 245  0
         while(i.hasNext())
 246  
         {
 247  0
             String s = (String) i.next();
 248  0
             Node n = (Node) projects.get( s );
 249  
 
 250  0
             cookies.add( n.getCookie() );
 251  0
         }
 252  
         
 253  0
         return cookies;
 254  
     }
 255  
 
 256  
     /**
 257  
      *  The recursive worker...
 258  
      */
 259  
     void doIt( String current )
 260  
         throws Exception
 261  
     {
 262  0
         Node project = (Node) projects.get(current);
 263  
 
 264  0
         if (project == null)
 265  
         {
 266  
             /*
 267  
              *  we may have a dependency that isn't a project.  
 268  
              *  so what... (This shouldn't happen)
 269  
              */
 270  
 
 271  0
             buildList.add( current );
 272  0
             return;
 273  
         }
 274  
 
 275  
         /*
 276  
          *  get the timestamp and compare.  If not the same, reset
 277  
          */
 278  
 
 279  0
         if ( project.getTimestamp() != currentTimestamp)
 280  
         {
 281  0
             project.setStatus( Node.ZILCH );
 282  
         }
 283  
 
 284  0
         project.setTimestamp( currentTimestamp );
 285  
 
 286  
         /*
 287  
          *  check status of this one
 288  
          */
 289  
 
 290  0
         int status = project.getStatus();
 291  
 
 292  0
         if ( status == Node.WORKING )
 293  
         {
 294  0
            throw new Exception("Detected loop while trying to build " + current);
 295  
         }
 296  0
         else if ( status == Node.ZILCH )
 297  
         {
 298  
             /*
 299  
              *   not working - so mark as working and start on the dependencies
 300  
              */
 301  0
             project.setStatus( Node.WORKING );
 302  
 
 303  
             /*
 304  
              *  do we have any dependencies?
 305  
              */
 306  0
             Iterator deps =  project.getDeps();
 307  
 
 308  
             /*
 309  
              *  if so, work on each
 310  
              */
 311  
 
 312  0
             while( deps.hasNext() )
 313  
             {
 314  0
                 String dep = (String) deps.next();
 315  0
                 Node depnode = (Node) projects.get( dep );
 316  
 
 317  0
                 if (depnode == null)
 318  
                 {
 319  
                     /*
 320  
                      *  we don't have this as a project, so 
 321  
                      *  let the client try to build it...
 322  
                      */
 323  
                     
 324  
                     // System.out.println("Adding non-project dep  build list : " + current );
 325  
 
 326  0
                     buildList.add( dep );
 327  0
                     continue;
 328  
                 }
 329  
                 
 330  
                 /*
 331  
                  *  get the timestamp and compare.  If not the same, reset
 332  
                  */
 333  
                                 
 334  0
                 if ( depnode.getTimestamp() != currentTimestamp)
 335  
                 {
 336  0
                     depnode.setStatus( Node.ZILCH );
 337  
                 }
 338  
                 
 339  0
                 depnode.setTimestamp( currentTimestamp );
 340  
 
 341  
                 /*
 342  
                  * now, look at the status of this dependency
 343  
                  */
 344  
 
 345  0
                 int depstatus = depnode.getStatus();
 346  
 
 347  0
                 if ( depstatus == Node.WORKING )
 348  
                 {
 349  
                     /*
 350  
                      *  gaak. loop!
 351  
                      */
 352  0
                     throw new Exception("LOOP : checking dep " + dep + " for current = " + current );
 353  
                 }
 354  0
                 else if (  depstatus == Node.ZILCH )
 355  
                 {
 356  
                     //                    System.out.println(" trying to build " + current + " : need to build dep " + dep );
 357  
                     
 358  
                     /*
 359  
                      *  recurse
 360  
                      */
 361  
 
 362  0
                     doIt( dep );
 363  
                 }
 364  0
                 else if(  depstatus == Node.DONE ) 
 365  
                 {
 366  
                     // can skip
 367  
                 }
 368  0
             }
 369  
             
 370  
             /*
 371  
              *  if all clear, can build and mark as done.  We don't care
 372  
              *  if the client couldn't do it for now.  That may change.
 373  
              *  the client can tell
 374  
              */
 375  
             
 376  
             //System.out.println("Adding to build list : " + current );
 377  
 
 378  0
             buildList.add( current );
 379  0
             project.setStatus( Node.DONE );
 380  
             
 381  0
             return;
 382  
         }
 383  
 
 384  
         /*
 385  
          *   node is done
 386  
          */
 387  
 
 388  0
         return; 
 389  
     }
 390  
 
 391  
     public void addProject(String project, List dependencies)
 392  
         throws Exception
 393  
     {
 394  0
         addProject(project, dependencies, project);
 395  0
     }
 396  
 
 397  
     /**
 398  
      *  Adds a project and it's associated dependencies.  The dependencies
 399  
      *  currently do not have to be projects themselves.
 400  
      *
 401  
      *  @param project  Name of project to add
 402  
      *  @param dependencies  java.util.List of project dependencies
 403  
      *  @throws Exception in the even that it already has the project in the list
 404  
      */
 405  
     public void addProject( String project, List dependencies, Object cookie )
 406  
         throws Exception
 407  
     {
 408  
         /*
 409  
          *  first, see if we have it
 410  
          */
 411  0
         Node n = (Node) projects.get( project );
 412  
 
 413  0
         if (n != null)
 414  
         {
 415  
             //System.out.println(" addProject() : rejecting duplicate : " + project );
 416  0
             throw new Exception("already have it...");
 417  
         }
 418  
 
 419  
         // System.out.println(" addProject() : adding project : " + project );
 420  
 
 421  
         /*
 422  
          *  make a new one and add the dependencies
 423  
          */
 424  0
         n = new Node( project, cookie );
 425  
 
 426  0
         Iterator i = dependencies.iterator();
 427  
 
 428  0
         while( i.hasNext() )
 429  
         {
 430  0
             String dep = (String) i.next();
 431  
 
 432  0
             if ( dep.equals( project ) )
 433  
             {
 434  
                 // System.out.println(" addProject() : rejecting self- dependency : " + project );
 435  
             }
 436  
             else
 437  
             {
 438  
                 // System.out.println(" addProject() :  adding dependency : " + dep + " for project : "  + project );
 439  0
                 n.addDep(  dep  );
 440  
             }
 441  0
         }
 442  
 
 443  
         /*
 444  
          * add to the pile
 445  
          */
 446  
 
 447  0
         projects.put( project, n );
 448  
 
 449  0
         return;
 450  
     }
 451  
 }
 452  
 
 453  
 class Node
 454  
 {
 455  0
     public static  int ZILCH = 0;
 456  0
     public static  int WORKING = 1;
 457  0
     public static  int DONE = 2;
 458  
 
 459  0
     private int status = ZILCH;
 460  0
     private ArrayList deps = new ArrayList();
 461  0
     private String name = "";
 462  0
     private Object cookie = null;
 463  0
     private long timestamp = 0;
 464  
 
 465  
     public Node( String name, Object cookie)
 466  0
     {
 467  0
         this.name = name;
 468  0
         this.cookie = cookie;
 469  0
     }
 470  
     
 471  
     public Object getCookie()
 472  
     {
 473  0
         return cookie;
 474  
     }
 475  
 
 476  
     public void addDep( String dep )
 477  
     {
 478  0
         deps.add( dep );
 479  0
     }
 480  
     
 481  
     public Iterator getDeps()
 482  
     {
 483  0
         return deps.iterator();
 484  
     }
 485  
     
 486  
     public void setStatus( int i )
 487  
     {
 488  0
         status = i;
 489  0
     }
 490  
     
 491  
     public int getStatus()
 492  
     {
 493  0
         return status;
 494  
     }
 495  
 
 496  
     public long getTimestamp()
 497  
     {
 498  0
         return timestamp;
 499  
     }
 500  
 
 501  
     public void setTimestamp( long t)
 502  
     {
 503  0
         timestamp = t;
 504  0
     }
 505  
 }
 506  
 
 507