Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 209434 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/emf/common/archive/Handler.java (-128 lines)
Removed Link Here
1
/**
2
 * <copyright> 
3
 *
4
 * Copyright (c) 2004-2005 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors: 
11
 *   IBM - Initial API and implementation
12
 *
13
 * </copyright>
14
 *
15
 * $Id$
16
 */
17
package org.eclipse.emf.common.archive;
18
19
import java.io.IOException;
20
import java.io.InputStream;
21
import java.net.URL;
22
import java.net.URLConnection;
23
import java.net.URLStreamHandler;
24
25
/**
26
 * A URL stream handler that can be {@link #register() registered} to support archive access protocol.
27
 * It uses {@link ArchiveURLConnection} to implement the connection.
28
 */
29
public class Handler extends URLStreamHandler
30
{
31
  /**
32
   * Registers this class.
33
   * A handler for protocol "xyz" is registered 
34
   * by providing a class named Handler implementing {@link URLStreamHandler}
35
   * in a package called named xyz in a package of your choosing,
36
   * and then registering that chosen prefix package name 
37
   * in the system property for <code>"java.protocol.handler.pkgs"</code>,
38
   * which is an "|" separated list of package prefixes to search for handlers.
39
   */
40
  public static void register()
41
  {
42
    String javaProtocolHandlerPkgs = System.getProperty("java.protocol.handler.pkgs");
43
    if (javaProtocolHandlerPkgs == null || javaProtocolHandlerPkgs.length() == 0)
44
    {
45
      javaProtocolHandlerPkgs = "org.eclipse.emf.common";
46
    }
47
    else
48
    {
49
      javaProtocolHandlerPkgs += "|org.eclipse.emf.common";
50
    }
51
    System.setProperty("java.protocol.handler.pkgs", javaProtocolHandlerPkgs); 
52
  }
53
  
54
  /**
55
   * Registers this handler and interprets each argument as URL to be opened, read in, and written out to System.out.
56
   * @param args URLs to open, read, and write to System.out
57
   * @throws IOException if there are problems opening or reading from the URLs, or writing to System.out.
58
   */
59
  public static void main(String[] args) throws IOException
60
  {
61
    register();
62
    
63
    for (int i = 0; i < args.length; ++i)
64
    {
65
      InputStream inputStream = new URL(args[i]).openStream();
66
      byte [] bytes = new byte [4048];
67
      for (int size; (size = inputStream.read(bytes, 0, bytes.length)) > -1; )
68
      {
69
        System.out.write(bytes, 0, size);
70
      }
71
    }
72
  }
73
  
74
  /**
75
   *  Creates an instance.
76
   */
77
  public Handler()
78
  {
79
    super();
80
  }
81
  
82
  /**
83
   * Overrides parsing the URL to validate constraints on well formed archive syntax.
84
   * @see URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
85
   */
86
  protected void parseURL(URL url, String specification, int start, int limit)
87
  {
88
    super.parseURL(url, specification, start, limit);
89
      
90
    // There needs to be another URL protocol right after the archive protocol, and not a "/".
91
    //
92
    if (start > limit || specification.charAt(start) == '/')
93
    {
94
      throw 
95
        new IllegalArgumentException
96
          ("archive protocol must be immediately followed by another URL protocol " + specification);
97
    }
98
    
99
    // There must be at least one archive path.
100
    //
101
    int archiveSeparator = specification.indexOf("!/", start);
102
    if (archiveSeparator < 0)
103
    {
104
      throw new IllegalArgumentException("missing archive separators " + specification.substring(start, limit));
105
    }
106
          
107
    // Parse to count the archive paths that must will be delegated to the nested URL based on the number of schemes at the start.
108
    //
109
    for (int i = start, end = specification.indexOf('/', start) - 1; (i = specification.indexOf(':', i)) < end; ++i)
110
    {
111
      // There should be at least one archive separator per scheme.
112
      //
113
      archiveSeparator = specification.indexOf("!/", archiveSeparator + 2);
114
      if (archiveSeparator < 0)
115
      {
116
        throw new IllegalArgumentException("too few archive separators " + specification);
117
      }
118
    }
119
  }
120
  
121
  /**
122
   *  Returns a new {@link ArchiveURLConnection}.
123
   */
124
  protected URLConnection openConnection(URL url) throws IOException
125
  {
126
    return new ArchiveURLConnection(url);
127
  }
128
}
(-)src/org/eclipse/emf/common/archive/package.html (-23 lines)
Removed Link Here
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
<html xmlns="http://www.w3.org/1999/xhtml">
4
<head>
5
<meta name="generator" content="HTML Tidy, see www.w3.org" />
6
<meta http-equiv="Content-Type"
7
content="text/html; charset=ISO-8859-1" /><!--
8
/**
9
 * <copyright>
10
 *
11
 * Copyright (c) 2005 IBM Corporation and others.
12
 * All rights reserved.   This program and the accompanying materials
13
 * are made available under the terms of the Eclipse Public License v1.0
14
 * which accompanies this distribution, and is available at
15
 * http://www.eclipse.org/legal/epl-v10.html
16
 * 
17
 * Contributors: 
18
 *   IBM - Initial API and implementation
19
 *
20
 * </copyright>
21
 *
22
 * $Id$
23
 */
(-)src/org/eclipse/emf/common/archive/ArchiveURLConnection.java (-553 lines)
Removed Link Here
1
/**
2
 * <copyright> 
3
 *
4
 * Copyright (c) 2004-2005 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors: 
11
 *   IBM - Initial API and implementation
12
 *
13
 * </copyright>
14
 *
15
 * $Id$
16
 */
17
package org.eclipse.emf.common.archive;
18
19
import java.io.File;
20
import java.io.FileInputStream;
21
import java.io.FileOutputStream;
22
import java.io.FilterInputStream;
23
import java.io.FilterOutputStream;
24
import java.io.IOException;
25
import java.io.InputStream;
26
import java.io.OutputStream;
27
import java.net.MalformedURLException;
28
import java.net.URL;
29
import java.net.URLConnection;
30
import java.util.zip.ZipEntry;
31
import java.util.zip.ZipFile;
32
import java.util.zip.ZipInputStream;
33
import java.util.zip.ZipOutputStream;
34
35
/**
36
 * A connection that can access an entry in an archive, and then recursively an entry in that archive, and so on.
37
 * For example, it can be used just like jar: or zip:, only the archive paths can repeat, e.g.,
38
 *<pre>
39
 *  archive:file:///c:/temp/example.zip!/org/example/nested.zip!/org/example/deeply-nested.html
40
 *</pre>
41
 * The general recursive pattern is
42
 *<pre>
43
 *  archive:$nestedURL${/!$archivePath$}+
44
 *</pre>
45
 * So the nested URL for the example above is
46
 *<pre>
47
 *  file:///c:/temp/example.zip
48
 *</pre>
49
 * 
50
 * <p>
51
 * Since the nested URL may itself contain archive schemes,
52
 * the subsequence of the archive paths that should be associated with the nested URL 
53
 * is determined by finding the nth archive separator, i.e., the nth !/, 
54
 * where n is the number of ":"s before the first "/" of the nested URL, i.e., the number of nested schemes.
55
 * For example, for a more complex case where the nested URL is itself an archive-based scheme, e.g.,
56
 *<pre>
57
 *  archive:jar:file:///c:/temp/example.zip!/org/example/nested.zip!/org/example/deeply-nested.html
58
 *</pre>
59
 * the nested URL is correctly parsed to skip to the second archive separator as
60
 *<pre>
61
 *  jar:file:///c:/temp/example.zip!/org/example/nested.zip
62
 *</pre>
63
 * </p>
64
 *
65
 * <p>
66
 * The logic for accessing archives can be tailored and reused independant from its usage as a URL connection.
67
 * This is normally done by using the constructor {@link #ArchiveURLConnection(String)}
68
 * and overriding {@link #createInputStream(String)} and {@link #createOutputStream(String)}.
69
 * The behavior can be tailored by overriding {@link #emulateArchiveScheme()} and {@link #useZipFile()}.
70
 * </p>
71
 */
72
public class ArchiveURLConnection extends URLConnection
73
{
74
  /**
75
   * The cached string version of the {@link #url URL}.
76
   */
77
  protected String urlString;
78
  
79
  /**
80
   * Constructs a new connection for the URL.
81
   * @param url the URL of this connection.
82
   */
83
  public ArchiveURLConnection(URL url)
84
  {
85
    super(url);
86
    urlString = url.toString();
87
  }
88
  
89
  /**
90
   * Constructs a new archive accessor.
91
   * This constructor forwards a null URL to be super constructor, 
92
   * so an instance built with this constructor <b>cannot</b> be used as a URLConnection.
93
   * The logic for accessing archives and for delegating to the nested URL can be reused in other applications,
94
   * without creating an URLs.
95
   * @param url the URL of the archive.
96
   */
97
  protected ArchiveURLConnection(String url)
98
  {
99
    super(null);
100
    urlString = url;
101
  }
102
  
103
  /**
104
   * </p>
105
   * Returns whether the implementation will handle all the archive accessors directly.
106
   * For example, whether
107
   *<pre>
108
   *  archive:jar:file:///c:/temp/example.zip!/org/example/nested.zip!/org/example/deeply-nested.html
109
   *</pre>
110
   * will be handled as if it were specified as
111
   *<pre>
112
   *  archive:file:///c:/temp/example.zip!/org/example/nested.zip!/org/example/deeply-nested.html
113
   *</pre>
114
   * Override this only if you are reusing the logic of retrieving an input stream into an archive 
115
   * and hence are likely to be overriding createInputStream, 
116
   * which is the point of delegation to the nested URL for recursive stream creation.
117
   * </p>
118
   * @return whether the implementation will handle all the archive accessors directly.
119
   */
120
  protected boolean emulateArchiveScheme()
121
  {
122
    return false;
123
  }
124
  
125
  /**
126
   * Returns whether to handle the special case of a nested URL with file: schema using a {@link ZipFile}.
127
   * This gives more efficient direct access to the root entry, e.g., 
128
   *<pre>
129
   *  archive:file:///c:/temp/example.zip!/org/example/nested.html
130
   *</pre>
131
   * @return whether to handle the special case of a nested URL with file: schema using a ZipFile.
132
   */
133
  protected boolean useZipFile()
134
  {
135
    return false;
136
  }
137
        
138
  /**
139
   * Record that this is connected.
140
   */
141
  public void connect() throws IOException
142
  {
143
    connected = true;
144
  }
145
  
146
  /**
147
   * Creates the input stream for the URL.
148
   * @return the input stream for the URL.
149
   */
150
  public InputStream getInputStream() throws IOException 
151
  {
152
    // There must be at least one archive path.
153
    //
154
    int archiveSeparator = urlString.indexOf("!/");
155
    if (archiveSeparator < 0)
156
    {
157
      throw new MalformedURLException("missing archive separators " + urlString);
158
    }
159
    
160
    // There needs to be another URL protocol right after the archive protocol, and not a "/".
161
    //
162
    int start = urlString.indexOf(':') + 1;
163
    if (start > urlString.length() || urlString.charAt(start) == '/')
164
    {
165
      throw 
166
        new IllegalArgumentException
167
          ("archive protocol must be immediately followed by another URL protocol " + urlString);
168
    }
169
    
170
    // Parse to extract the archives that will be delegated to the nested URL based on the number of schemes at the start.
171
    //
172
    for (int i = start, end = urlString.indexOf("/") - 1; (i = urlString.indexOf(":", i)) < end; )
173
    {
174
      if (emulateArchiveScheme())
175
      {
176
        // Skip a scheme for the achive accessor to be handled directly here.
177
        //
178
        start = ++i;
179
      }
180
      else
181
      {
182
        // Skip an archive accessor to be handled by delegation to the scheme in nested URL.
183
        //
184
        archiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
185
        if (archiveSeparator < 0)
186
        {
187
          throw new MalformedURLException("too few archive separators " + urlString);
188
        }
189
        ++i;
190
      }
191
    }
192
          
193
    // System.out.println("archive: " + urlString.substring(start, archiveSeparator) + " -> " + urlString.substring(archiveSeparator + 2));
194
          
195
    // Create the delegate URL.
196
    //
197
    String nestedURL = urlString.substring(start, archiveSeparator);
198
          
199
    // The cutoff point to the next archive.
200
    //
201
    int nextArchiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
202
          
203
    // Construct the input stream in a special efficient way for case of a file scheme.
204
    //
205
    InputStream inputStream;
206
    if (!useZipFile() || !nestedURL.startsWith("file:"))
207
    {
208
      // Just get the stream from the URL.
209
      //
210
      inputStream =  createInputStream(nestedURL);
211
    }
212
    else
213
    {
214
      // The name to be used for the entry.
215
      //
216
      String entry = 
217
         nextArchiveSeparator < 0 ?
218
           urlString.substring(archiveSeparator + 2) :
219
           urlString.substring(archiveSeparator + 2, nextArchiveSeparator);
220
                 
221
      // Skip over this archive path to the next one, since we are handling this one special.
222
      //
223
      archiveSeparator = nextArchiveSeparator;
224
      nextArchiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
225
            
226
      // Go directly to the right entry in the zip file, 
227
      // get the stream, 
228
      // and wrap it so that closing it closes the zip file.
229
      //
230
      final ZipFile zipFile = new ZipFile(nestedURL.substring(5));
231
      ZipEntry zipEntry = zipFile.getEntry(entry);
232
      if (zipEntry == null)
233
      {
234
        throw new IOException("archive entry not found " + entry);
235
      }
236
      inputStream = 
237
        new FilterInputStream(zipFile.getInputStream(zipEntry))
238
        {
239
          public void close() throws IOException
240
          {
241
            super.close();
242
            zipFile.close();
243
          }
244
        };
245
    }
246
          
247
    // Loop over the archive paths.
248
    //
249
    LOOP:
250
    while (archiveSeparator > 0)
251
    {
252
      // The entry name to be matched.
253
      //
254
      String entry = 
255
         nextArchiveSeparator < 0 ?
256
           urlString.substring(archiveSeparator + 2) :
257
           urlString.substring(archiveSeparator + 2, nextArchiveSeparator);
258
            
259
      // Wrap the input stream as a zip stream to scan it's contents for a match.
260
      //
261
      ZipInputStream zipInputStream = new ZipInputStream(inputStream);
262
      while (zipInputStream.available() >= 0)
263
      {
264
        ZipEntry zipEntry = zipInputStream.getNextEntry();
265
        if (zipEntry == null)
266
        {
267
          break;
268
        }
269
        else if (entry.equals(zipEntry.getName()))
270
        {
271
          inputStream = zipInputStream;
272
                  
273
          // Skip to the next archive path and continue the loop.
274
          //
275
          archiveSeparator = nextArchiveSeparator;
276
          nextArchiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
277
          continue LOOP;
278
        }
279
      }
280
            
281
      // Unless we matched an entry, we're done.
282
      //
283
      break;
284
    }
285
          
286
    return inputStream;
287
  }
288
  
289
  /**
290
   * Creates an input stream for the nested URL by calling {@link URL#openStream()opening} a stream on it.
291
   * @param nestedURL the nested URL for which a stream is required.
292
   * @return the open stream of the nested URL.
293
   */
294
  protected InputStream createInputStream(String nestedURL) throws IOException
295
  {
296
    return new URL(nestedURL).openStream();
297
  }
298
  
299
  /**
300
   * Creates the output stream for the URL.
301
   * @return the output stream for the URL.
302
   */
303
  public OutputStream getOutputStream() throws IOException
304
  {
305
    // There must be at least one archive separator.
306
    //
307
    int archiveSeparator = urlString.indexOf("!/");
308
    if (archiveSeparator < 0)
309
    {
310
      throw new MalformedURLException("missing archive separator in " + urlString);
311
    }
312
    
313
    // There needs to be another URL protocol right after the archive protocol, and not a "/".
314
    //
315
    int start = urlString.indexOf(':') + 1;
316
    if (start > urlString.length() || urlString.charAt(start) == '/')
317
    {
318
      throw 
319
        new IllegalArgumentException
320
          ("archive protocol must be immediately followed by another URL protocol " + urlString);
321
    }
322
    
323
    // Parse the URI to extract the nested/delegate URI based on preference and the number of schemes at the start.
324
    //
325
    for (int i = start, end = urlString.indexOf("/") - 1; (i = urlString.indexOf(":", i)) < end; )
326
    {
327
      if (emulateArchiveScheme())
328
      {
329
        // Skip a scheme for the achive accessor to be handled directly here.
330
        //
331
        start = ++i;
332
      }
333
      else
334
      {
335
        // Skip an archive accessor to be handled by delegation to the scheme in nested URI.
336
        //
337
        archiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
338
        if (archiveSeparator < 0)
339
        {
340
          throw new MalformedURLException("too few archive separators in " + urlString);
341
        }
342
        ++i;
343
      }
344
    }
345
    
346
    // System.out.println("archive: -> " + urlString.substring(start, archiveSeparator) + " -> " + urlString.substring(archiveSeparator + 2));
347
    
348
    // Create the delegate URL
349
    //
350
    final String nestedURL = urlString.substring(start, archiveSeparator);
351
    
352
    // Create a temporary file where the existing contents of the archive can be written 
353
    // before the new contents are added.
354
    //
355
    final File tempFile = File.createTempFile("Archive", "zip");
356
    
357
    // Record the input and output streams for closing in case of failure so that handles are not left open.
358
    //
359
    InputStream sourceInputStream =  null;
360
    OutputStream tempOutputStream = null;
361
    try
362
    {
363
      // Create the output stream to the temporary file and the input stream for the delegate URL.
364
      //
365
      tempOutputStream = new FileOutputStream(tempFile);
366
      try
367
      {
368
        sourceInputStream =  createInputStream(nestedURL);
369
      }
370
      catch (IOException exception)
371
      {
372
        // Continue processing if the file doesn't exist so that we try create a new empty one.
373
      }
374
      
375
      // Record them as generic streams to record state during the loop that emulates recursion.
376
      //
377
      OutputStream outputStream = tempOutputStream;
378
      InputStream inputStream =  sourceInputStream;
379
      
380
      // The cutoff point to the next archive.
381
      //
382
      int nextArchiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
383
      
384
      // The most deeply nested output stream that will be returned wrapped as the result.
385
      //
386
      ZipOutputStream zipOutputStream;
387
      
388
      // A buffer for transferring archive contents.
389
      //
390
      final byte [] bytes = new byte [4096];
391
              
392
      // We expect there to be at least one archive path.
393
      //
394
      do
395
      {
396
        // The name that will be used as the archive entry.
397
        //
398
        String entry = 
399
           nextArchiveSeparator < 0 ?
400
             urlString.substring(archiveSeparator + 2) :
401
             urlString.substring(archiveSeparator + 2, nextArchiveSeparator);
402
             
403
        // Wrap the current result as a zip stream, and record it for loop-based recursion.
404
        //
405
        zipOutputStream =  new ZipOutputStream(outputStream);
406
        outputStream = zipOutputStream;
407
        
408
        // Wrap the current input as a zip stream, and record it for loop-based recursion.
409
        //
410
        ZipInputStream zipInputStream = inputStream == null ? null : new ZipInputStream(inputStream);
411
        inputStream = zipInputStream;
412
        
413
        // Loop over the entries in the zip stream.
414
        //
415
        while (zipInputStream != null && zipInputStream.available() >= 0)
416
        {
417
          // If this entry isn't the end marker 
418
          // and isn't the matching one that we are replacing...
419
          //
420
          ZipEntry zipEntry = zipInputStream.getNextEntry();
421
          if (zipEntry == null)
422
          {
423
            break;
424
          }
425
          else if (!entry.equals(zipEntry.getName()))
426
          {
427
            // Transfer the entry and its contents.
428
            //
429
            zipOutputStream.putNextEntry(zipEntry);
430
            for (int size; (size = zipInputStream.read(bytes, 0, bytes.length)) > -1; )
431
            {
432
              zipOutputStream.write(bytes, 0, size);
433
            }
434
          }
435
        }
436
        
437
        // Create a new or replaced entry.
438
        //
439
        zipOutputStream.putNextEntry(new ZipEntry(entry));
440
        
441
        // Find the next archive path and continue "recursively" if there is one.
442
        //
443
        archiveSeparator = nextArchiveSeparator;
444
        nextArchiveSeparator = urlString.indexOf("!/", archiveSeparator + 2);
445
      }
446
      while (archiveSeparator > 0);
447
      
448
      // Ensure that it won't be closed in the finally block.
449
      //
450
      tempOutputStream = null;
451
      
452
      // Wrap the deepest result so that on close, the results are finally transferred.
453
      //
454
      final boolean deleteRequired = sourceInputStream != null;
455
      return
456
        new FilterOutputStream(zipOutputStream)
457
        {
458
          protected boolean isClosed;
459
          
460
          public void close() throws IOException
461
          {
462
            // Make sure we close only once.
463
            //
464
            if (!isClosed)
465
            {
466
              isClosed = true;
467
              
468
              // Close for real so that the temporary file is ready to be read.
469
              //
470
              super.close();
471
              
472
              boolean useRenameTo = nestedURL.startsWith("file:");
473
              
474
              // If the delegate URI can be handled as a file, 
475
              // we'll hope that renaming it will be really efficient.
476
              //
477
              if (useRenameTo)
478
              {
479
                File targetFile = new File(nestedURL.substring(5));
480
                if (deleteRequired && !targetFile.delete())
481
                {
482
                  throw new IOException("cannot delete " + targetFile.getPath());
483
                }
484
                else if (!tempFile.renameTo(targetFile))
485
                {
486
                  useRenameTo = false;
487
                }
488
              }
489
              if (!useRenameTo)
490
              {
491
                // Try to transfer it by reading the contents of the temporary file 
492
                // and writing them to the output stream of the delegate.
493
                //
494
                InputStream inputStream = null;
495
                OutputStream outputStream = null;
496
                try
497
                {
498
                  inputStream = new FileInputStream(tempFile);
499
                  outputStream = createOutputStream(nestedURL);
500
                  for (int size; (size = inputStream.read(bytes, 0, bytes.length)) > -1; )
501
                  {
502
                    outputStream.write(bytes, 0, size);
503
                  }
504
                }
505
                finally
506
                {
507
                  // Make sure they are closed no matter what bad thing happens.
508
                  //
509
                  if (inputStream != null) 
510
                  {
511
                    inputStream.close();
512
                  }
513
                  if (outputStream != null) 
514
                  {
515
                    outputStream.close();
516
                  }
517
                }
518
              }
519
            }
520
          }
521
       };
522
    }
523
    finally
524
    {
525
      // Close in case of failure to complete.
526
      //
527
      if (tempOutputStream != null)
528
      {
529
        tempOutputStream.close();
530
      }
531
      
532
      // Close if we created this.
533
      //
534
      if (sourceInputStream != null)
535
      {
536
        sourceInputStream.close();
537
      }
538
    }
539
  }
540
  
541
  /**
542
   * Creates an input stream for the nested URL by calling {@link URL#openStream()opening} a stream on it.
543
   * @param nestedURL the nested URL for which a stream is required.
544
   * @return the open stream of the nested URL.
545
   */
546
  protected OutputStream createOutputStream(String nestedURL) throws IOException
547
  {
548
    URL url = new URL(nestedURL.toString());
549
    URLConnection urlConnection = url.openConnection();
550
    urlConnection.setDoOutput(true);
551
    return urlConnection.getOutputStream(); 
552
  }
553
}
(-).classpath (-4 / +4 lines)
Lines 1-7 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
1
<?xml version="1.0" encoding="UTF-8"?>
2
<classpath>
2
<classpath>
3
    <classpathentry kind="src" path="src/"/>
3
	<classpathentry kind="src" path="src"/>
4
    <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
4
	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
5
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
5
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
6
    <classpathentry kind="output" path="bin"/>
6
	<classpathentry kind="output" path="bin"/>
7
</classpath>
7
</classpath>
(-)src/org/eclipse/emf/common/util/BasicEList.java (-51 / +63 lines)
Lines 17-27 Link Here
17
package org.eclipse.emf.common.util;
17
package org.eclipse.emf.common.util;
18
18
19
19
20
import java.io.IOException;
20
//XXX GWT CHANGE
21
import java.io.ObjectInputStream;
21
//import java.io.IOException;
22
import java.io.ObjectOutputStream;
22
//import java.io.ObjectInputStream;
23
//import java.io.ObjectOutputStream;
23
import java.io.Serializable;
24
import java.io.Serializable;
24
import java.lang.reflect.Array;
25
//import java.lang.reflect.Array;
25
import java.util.AbstractList;
26
import java.util.AbstractList;
26
import java.util.Collection;
27
import java.util.Collection;
27
import java.util.ConcurrentModificationException;
28
import java.util.ConcurrentModificationException;
Lines 47-52 Link Here
47
   */
48
   */
48
  protected transient Object data[];
49
  protected transient Object data[];
49
50
51
//XXX GWT CHANGE (modcount not available in upstream GWT maybe a feature request
52
// should be raised)
53
  protected transient int modCount = 0;
54
50
  /**
55
  /**
51
   * Creates an empty instance with no initial capacity.
56
   * Creates an empty instance with no initial capacity.
52
   * The data storage will be null.
57
   * The data storage will be null.
Lines 444-450 Link Here
444
    {
449
    {
445
      if (array.length < size)
450
      if (array.length < size)
446
      {
451
      {
447
        array = (Object[])Array.newInstance(array.getClass().getComponentType(), size);
452
//FIXME GWT CHANGE DO WE NEED TO FIX THIS?
453
    	  array = new Object[size];
454
//        array = (Object[])Array.newInstance(array.getClass().getComponentType(), size);
448
      }
455
      }
449
  
456
  
450
      System.arraycopy(data, 0, array, 0, size);
457
      System.arraycopy(data, 0, array, 0, size);
Lines 1071-1114 Link Here
1071
    }
1078
    }
1072
  }
1079
  }
1073
1080
1074
  private synchronized void writeObject(ObjectOutputStream objectOutputStream) throws IOException
1081
//XXX GWT CHANGE Serialization not available
1075
  {
1082
//  private synchronized void writeObject(ObjectOutputStream objectOutputStream) throws IOException
1076
    objectOutputStream.defaultWriteObject();
1083
//  {
1077
    if (data == null)
1084
//    objectOutputStream.defaultWriteObject();
1078
    {
1085
//    if (data == null)
1079
      objectOutputStream.writeInt(0);
1086
//    {
1080
    }
1087
//      objectOutputStream.writeInt(0);
1081
    else
1088
//    }
1082
    {
1089
//    else
1083
      objectOutputStream.writeInt(data.length);
1090
//    {
1084
      for (int i = 0; i < size; ++i)
1091
//      objectOutputStream.writeInt(data.length);
1085
      {
1092
//      for (int i = 0; i < size; ++i)
1086
        objectOutputStream.writeObject(data[i]);
1093
//      {
1087
      }
1094
//        objectOutputStream.writeObject(data[i]);
1088
    }
1095
//      }
1089
  }
1096
//    }
1090
1097
//  }
1091
  private synchronized void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException
1098
//
1092
  {
1099
//  private synchronized void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException
1093
    objectInputStream.defaultReadObject();
1100
//  {
1094
    int arrayLength = objectInputStream.readInt();
1101
//    objectInputStream.defaultReadObject();
1095
    if (arrayLength > 0)
1102
//    int arrayLength = objectInputStream.readInt();
1096
    {
1103
//    if (arrayLength > 0)
1097
      try
1104
//    {
1098
      {
1105
//      try
1099
        data = newData(arrayLength);
1106
//      {
1100
      }
1107
//        data = newData(arrayLength);
1101
      catch (Throwable exception)
1108
//      }
1102
      {
1109
//      catch (Throwable exception)
1103
        data = new Object[arrayLength];
1110
//      {
1104
      }
1111
//        data = new Object[arrayLength];
1105
1112
//      }
1106
      for (int i = 0; i < size; ++i)
1113
//
1107
      {
1114
//      for (int i = 0; i < size; ++i)
1108
        didAdd(i, assign(i, objectInputStream.readObject()));
1115
//      {
1109
      }
1116
//        didAdd(i, assign(i, objectInputStream.readObject()));
1110
    }
1117
//      }
1111
  }
1118
//    }
1119
//  }
1112
1120
1113
  /**
1121
  /**
1114
   * Returns a shallow copy of this list.
1122
   * Returns a shallow copy of this list.
Lines 1116-1124 Link Here
1116
   */
1124
   */
1117
  public Object clone() 
1125
  public Object clone() 
1118
  {
1126
  {
1119
    try 
1127
//FIXME GWT CHANGE .clone is not supported by GWT
1120
    {
1128
// but creating a new list is not 100% the same!
1121
      BasicEList clone = (BasicEList)super.clone();
1129
// Should we raise a bug against GWT and ask for clone-support for lists?
1130
//    try
1131
//    {
1132
//      BasicEList clone = (BasicEList)super.clone();
1133
      BasicEList clone = new BasicEList(this);
1122
      if (size > 0)
1134
      if (size > 0)
1123
      {
1135
      {
1124
        clone.size = size;
1136
        clone.size = size;
Lines 1126-1136 Link Here
1126
        System.arraycopy(data, 0, clone.data, 0, size);
1138
        System.arraycopy(data, 0, clone.data, 0, size);
1127
      }
1139
      }
1128
      return clone;
1140
      return clone;
1129
    } 
1141
//    }
1130
    catch (CloneNotSupportedException exception) 
1142
//    catch (CloneNotSupportedException exception)
1131
    { 
1143
//    {
1132
      throw new InternalError();
1144
//      throw new InternalError();
1133
    }
1145
//    }
1134
  }
1146
  }
1135
1147
1136
  /**
1148
  /**
(-)src/org/eclipse/emf/common/util/ResourceLocator.java (-74 / +2 lines)
Lines 1-79 Link Here
1
/**
2
 * <copyright> 
3
 *
4
 * Copyright (c) 2002-2004 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors: 
11
 *   IBM - Initial API and implementation
12
 *
13
 * </copyright>
14
 *
15
 * $Id: ResourceLocator.java,v 1.3 2005/06/08 06:19:08 nickb Exp $
16
 */
17
package org.eclipse.emf.common.util;
1
package org.eclipse.emf.common.util;
18
2
3
public interface ResourceLocator {
19
4
20
import java.net.URL;
5
	String getString(String string, Object[] objects);
21
6
22
23
/**
24
 * A locator of Java resources.
25
 */
26
public interface ResourceLocator
27
{
28
  /** 
29
   * Returns the URL from which all resources are based.
30
   * @return the URL from which all resources are based.
31
   */
32
  URL getBaseURL();
33
34
  /**
35
   * Returns the description that can be used to create the image resource associated with the key.
36
   * The description will typically be in the form of a URL to the image data.
37
   * Creation of an actual image depends on the GUI environment;
38
   * within Eclipse, org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry can be used.
39
   * @param key the key of the image resource.
40
   * @return the description on the image resource.
41
   */
42
  Object getImage(String key);
43
44
  /**
45
   * Returns the string resource associated with the key.
46
   * @param key the key of the string resource.
47
   * @return the string resource associated with the key.
48
   */
49
  String getString(String key);
50
51
  /**
52
   * Returns the string resource associated with the key.
53
   * @param key the key of the string resource.
54
   * @param translate whether the result is to be translated to the current locale.
55
   * @return the string resource associated with the key.
56
   */
57
  String getString(String key, boolean translate);
58
59
  /**
60
   * Returns a string resource associated with the key, and peforms substitutions.
61
   * @param key the key of the string.
62
   * @param substitutions the message substitutions.
63
   * @return a string resource associated with the key.
64
   * @see #getString(String)
65
   * @see java.text.MessageFormat#format(String, Object[])
66
   */
67
  String getString(String key, Object [] substitutions);
68
69
  /**
70
   * Returns a string resource associated with the key, and peforms substitutions.
71
   * @param key the key of the string.
72
   * @param substitutions the message substitutions.
73
   * @param translate whether the result is to be translated to the current locale.
74
   * @return a string resource associated with the key.
75
   * @see #getString(String)
76
   * @see java.text.MessageFormat#format(String, Object[])
77
   */
78
  String getString(String key, Object [] substitutions, boolean translate);
79
}
7
}
(-)src/org/eclipse/emf/common/util/BasicMonitor.java (-386 lines)
Removed Link Here
1
/**
2
 * <copyright>
3
 *
4
 * Copyright (c) 2005 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 *
10
 * Contributors:
11
 *   IBM - Initial API and implementation
12
 *
13
 * </copyright>
14
 *
15
 * $Id: BasicMonitor.java,v 1.1 2005/11/18 12:01:19 emerks Exp $
16
 */
17
package org.eclipse.emf.common.util;
18
19
import java.io.PrintStream;
20
21
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
23
import org.eclipse.core.runtime.IStatus;
24
import org.eclipse.core.runtime.SubProgressMonitor;
25
26
27
/**
28
 * The most basic implementation of a task monitor.
29
 */
30
public class BasicMonitor implements Monitor 
31
{
32
  private boolean isCanceled;
33
  
34
  private Diagnostic blockedReason;
35
  
36
  public BasicMonitor()
37
  {
38
  }
39
40
  public boolean isCanceled()
41
  {
42
    return isCanceled;
43
  }
44
45
  public void setCanceled(boolean isCanceled)
46
  {
47
    this.isCanceled = isCanceled;
48
  }
49
  
50
  /**
51
   * Returns the current reason for task being blocked, or <code>null</code>.
52
   */
53
  public Diagnostic getBlockedReason()
54
  {
55
    return blockedReason;
56
  }
57
  
58
  public void setBlocked(Diagnostic reason)
59
  {
60
    this.blockedReason = reason;
61
  }
62
63
  public void clearBlocked()
64
  {
65
    this.blockedReason = null;
66
  }
67
 
68
  public void beginTask(String name, int totalWork)
69
  {
70
  }
71
  
72
  public void setTaskName(String name)
73
  {
74
  }
75
76
  public void subTask(String name)
77
  {
78
  }
79
80
  public void worked(int work)
81
  {
82
  }
83
  
84
  public void internalWorked(double work)
85
  {
86
  }
87
    
88
  public void done()
89
  {
90
  }
91
  
92
  /**
93
   * A simple monitor that delegates to another monitor.
94
   */
95
  public static class Delegating
96
  {
97
    protected Monitor monitor;
98
    
99
    public Delegating(Monitor monitor)
100
    {
101
      this.monitor = monitor; 
102
    }
103
    
104
    public boolean isCanceled()
105
    {
106
      return monitor.isCanceled();
107
    }
108
109
    public void setCanceled(boolean value)
110
    {
111
      monitor.setCanceled(value);
112
    }
113
114
    public void setBlocked(Diagnostic reason)
115
    {
116
      monitor.setBlocked(reason);
117
    }
118
    
119
    public void clearBlocked()
120
    {
121
      monitor.clearBlocked();
122
    }
123
124
    public void beginTask(String name, int totalWork)
125
    {
126
      monitor.beginTask(name, totalWork);
127
    }
128
129
    public void setTaskName(String name)
130
    {
131
      monitor.setTaskName(name);
132
    }
133
134
    public void subTask(String name)
135
    {
136
      monitor.subTask(name);
137
    }
138
139
    public void worked(int work)
140
    {
141
      monitor.worked(work);
142
    }
143
    
144
    public void internalWorked(double work)
145
    {
146
      monitor.internalWorked(work);
147
    }
148
149
    public void done()
150
    {
151
      monitor.done();
152
    }
153
    
154
    /**
155
     * A simple monitor that delegates to another monitor, and implements the Eclipse API
156
     */
157
    private static class Eclipse extends Delegating implements IProgressMonitorWithBlocking
158
    {
159
      public Eclipse(Monitor monitor)
160
      {
161
        super(monitor);
162
      }
163
      
164
      public void setBlocked(IStatus reason)
165
      {
166
        setBlocked
167
          (new BasicDiagnostic
168
              (reason.getSeverity(), 
169
               reason.getPlugin(), 
170
               reason.getCode(), 
171
               reason.getMessage(), 
172
               null));
173
      }
174
  
175
      public static IProgressMonitorWithBlocking createIProgressMonitorWithBlocking(Monitor monitor)
176
      {
177
        if (monitor instanceof IProgressMonitorWithBlocking)
178
        {
179
          return (IProgressMonitorWithBlocking)monitor;
180
        }
181
        else
182
        {
183
          return new Eclipse(monitor);
184
        }
185
      }
186
      
187
      public static IProgressMonitor createIProgressMonitor(Monitor monitor)
188
      {
189
        if (monitor instanceof IProgressMonitor)
190
        {
191
          return (IProgressMonitor)monitor;
192
        }
193
        else
194
        {
195
          return new Eclipse(monitor);
196
        }
197
      }
198
    }
199
  }
200
  
201
  /**
202
   * Creates a delegating wrapper that allows the monitor to be used 
203
   * in a context requiring an instance implementing the Eclipse API.
204
   */
205
  public static IProgressMonitor toIProgressMonitor(Monitor monitor)
206
  {
207
    return Delegating.Eclipse.createIProgressMonitor(monitor);
208
  }
209
  
210
  /**
211
   * Creates a delegating wrapper that allows the monitor to be used 
212
   * in a context requiring an instance implementing the Eclipse API.
213
   */
214
  public static IProgressMonitorWithBlocking toIProgressMonitorWithBlocking(Monitor monitor)
215
  {
216
    return Delegating.Eclipse.createIProgressMonitorWithBlocking(monitor);
217
  }
218
  
219
  /**
220
   * A simple monitor that delegates to another Eclipse monitor.
221
   */
222
  private static class EclipseDelegating implements Monitor
223
  {
224
    protected IProgressMonitor progressMonitor;
225
    protected IProgressMonitorWithBlocking progressMonitorWithBlocking;
226
    
227
    public EclipseDelegating(IProgressMonitor progressMonitor)
228
    {
229
      this.progressMonitor = progressMonitor; 
230
      if (progressMonitor instanceof IProgressMonitorWithBlocking)
231
      {
232
        this.progressMonitorWithBlocking = (IProgressMonitorWithBlocking)progressMonitor;
233
      }
234
    }
235
    
236
    public EclipseDelegating(IProgressMonitorWithBlocking progressMonitorWithBlocking)
237
    {
238
      this.progressMonitor = progressMonitorWithBlocking; 
239
      this.progressMonitorWithBlocking = progressMonitorWithBlocking; 
240
    }
241
    
242
    public boolean isCanceled()
243
    {
244
      return progressMonitor.isCanceled();
245
    }
246
247
    public void setCanceled(boolean value)
248
    {
249
      progressMonitor.setCanceled(value);
250
    }
251
252
    public void setBlocked(Diagnostic reason)
253
    {
254
      if (progressMonitorWithBlocking != null)
255
      {
256
        progressMonitorWithBlocking.setBlocked(BasicDiagnostic.toIStatus(reason));
257
      }
258
    }
259
260
    public void clearBlocked()
261
    {
262
      if (progressMonitorWithBlocking != null)
263
      {
264
        progressMonitorWithBlocking.clearBlocked();
265
      }
266
    }
267
268
    public void beginTask(String name, int totalWork)
269
    {
270
      progressMonitor.beginTask(name, totalWork);
271
    }
272
    
273
    public void setTaskName(String name)
274
    {
275
      progressMonitor.setTaskName(name);
276
    }
277
278
    public void subTask(String name)
279
    {
280
      progressMonitor.subTask(name);
281
    }
282
283
    public void worked(int work)
284
    {
285
      progressMonitor.worked(work);
286
    }
287
    
288
    public void internalWorked(double work)
289
    {
290
      progressMonitor.internalWorked(work);
291
    }
292
293
    public void done()
294
    {
295
      progressMonitor.done();
296
    }
297
  }
298
  
299
  /**
300
   * Creates a delegating wrapper that allows the Eclipse progress monitor to be used 
301
   * in a context requiring an instance implementing the monitor API.
302
   */
303
  public static Monitor toMonitor(IProgressMonitorWithBlocking progressMonitor)
304
  {
305
    return new EclipseDelegating(progressMonitor);
306
  }
307
  
308
  /**
309
   * Creates a delegating wrapper that allows the Eclipse progress monitor to be used 
310
   * in a context requiring an instance implementing the monitor API.
311
   */
312
  public static Monitor toMonitor(IProgressMonitor progressMonitor)
313
  {
314
    return new EclipseDelegating(progressMonitor);
315
  }
316
  
317
  /**
318
   * An Eclipse subprogress monitor that directly implements the monitor API.
319
   */
320
  public static class EclipseSubProgress extends SubProgressMonitor implements Monitor
321
  {
322
    public EclipseSubProgress(IProgressMonitor monitor, int ticks)
323
    {
324
      super(monitor, ticks);
325
    }
326
327
    public EclipseSubProgress(IProgressMonitor monitor, int ticks, int style)
328
    {
329
      super(monitor, ticks, style);
330
    }
331
332
    public void setBlocked(Diagnostic reason)
333
    {
334
      super.setBlocked(BasicDiagnostic.toIStatus(reason));
335
    }
336
  }
337
  
338
  /**
339
   * A simple monitor that prints progress to a print stream.
340
   */
341
  public static class Printing extends BasicMonitor
342
  {
343
    protected PrintStream printStream;
344
345
    public Printing(PrintStream printStream)
346
    {
347
      this.printStream = printStream;
348
    }
349
350
    public void beginTask(String name, int totalWork)
351
    {
352
      if (name != null && name.length() != 0)
353
      {
354
        printStream.println(">>> " + name);
355
      }
356
    }
357
358
    public void setTaskName(String name)
359
    {
360
      if (name != null && name.length() != 0)
361
      {
362
        printStream.println("<>> " + name);
363
      }
364
    }
365
366
    public void subTask(String name)
367
    {
368
      if (name != null && name.length() != 0)
369
      {
370
        printStream.println(">>  " + name);
371
      }
372
    }
373
    
374
    public void setBlocked(Diagnostic reason)
375
    {
376
      super.setBlocked(reason);
377
      printStream.println("#>  " + reason.getMessage());
378
    }
379
  
380
    public void clearBlocked()
381
    {
382
      printStream.println("=>  " + getBlockedReason().getMessage());
383
      super.clearBlocked();
384
    }
385
  }
386
}
(-)src/org/eclipse/emf/common/util/URI.java (-150 / +163 lines)
Lines 1-13 Link Here
1
/**
1
/**
2
 * <copyright> 
2
 * <copyright>
3
 *
3
 *
4
 * Copyright (c) 2002-2005 IBM Corporation and others.
4
 * Copyright (c) 2002-2005 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
9
 *
10
 * Contributors: 
10
 * Contributors:
11
 *   IBM - Initial API and implementation
11
 *   IBM - Initial API and implementation
12
 *
12
 *
13
 * </copyright>
13
 * </copyright>
Lines 16-29 Link Here
16
 */
16
 */
17
package org.eclipse.emf.common.util;
17
package org.eclipse.emf.common.util;
18
18
19
import java.io.File;
19
//import java.io.File;
20
import java.lang.ref.WeakReference;
20
//import java.lang.ref.WeakReference;
21
import java.util.ArrayList;
21
import java.util.ArrayList;
22
import java.util.Arrays;
22
import java.util.Arrays;
23
import java.util.Collections;
23
import java.util.Collections;
24
import java.util.HashMap;
24
import java.util.HashMap;
25
import java.util.HashSet;
25
import java.util.HashSet;
26
import java.util.Iterator;
26
//import java.util.Iterator;
27
import java.util.List;
27
import java.util.List;
28
import java.util.Map;
28
import java.util.Map;
29
import java.util.Set;
29
import java.util.Set;
Lines 75-81 Link Here
75
 * can be used, in which a non-null <code>device</code> parameter can be
75
 * can be used, in which a non-null <code>device</code> parameter can be
76
 * specified.
76
 * specified.
77
 *
77
 *
78
 * <p><a name="archive_explanation"> 
78
 * <p><a name="archive_explanation">
79
 * The other enhancement provides support for the almost-hierarchical
79
 * The other enhancement provides support for the almost-hierarchical
80
 * form used for files within archives, such as the JAR scheme, defined
80
 * form used for files within archives, such as the JAR scheme, defined
81
 * for the Java Platform in the documentation for {@link
81
 * for the Java Platform in the documentation for {@link
Lines 103-109 Link Here
103
 * createURI(String) createURI} to have parsed them correctly from a single
103
 * createURI(String) createURI} to have parsed them correctly from a single
104
 * URI string.  If necessary in the future, these tests may be made more
104
 * URI string.  If necessary in the future, these tests may be made more
105
 * strict, to better coform to the RFC.
105
 * strict, to better coform to the RFC.
106
 * 
106
 *
107
 * <p>Another group of static methods, whose names begin with "encode", use
107
 * <p>Another group of static methods, whose names begin with "encode", use
108
 * percent escaping to encode any characters that are not permitted in the
108
 * percent escaping to encode any characters that are not permitted in the
109
 * various URI components. Another static method is provided to {@link
109
 * various URI components. Another static method is provided to {@link
Lines 153-203 Link Here
153
  private final boolean absolutePath;
153
  private final boolean absolutePath;
154
  private final String[] segments; // empty last segment -> trailing separator
154
  private final String[] segments; // empty last segment -> trailing separator
155
  private final String query;
155
  private final String query;
156
  private static final char File_separatorChar = '/';
156
157
157
  // A cache of URIs, keyed by the strings from which they were created.
158
  // A cache of URIs, keyed by the strings from which they were created.
158
  // The fragment of any URI is removed before caching it here, to minimize
159
  // The fragment of any URI is removed before caching it here, to minimize
159
  // the size of the cache in the usual case where most URIs only differ by
160
  // the size of the cache in the usual case where most URIs only differ by
160
  // the fragment.
161
  // the fragment.
161
  private static final Map uriCache = 
162
  private static final Map uriCache =
162
    new HashMap()
163
    new HashMap()
163
    {
164
//    {
164
      static final int MIN_LIMIT = 1000;
165
//      static final int MIN_LIMIT = 1000;
165
      int count;
166
//      int count;
166
      int limit = MIN_LIMIT;
167
//      int limit = MIN_LIMIT;
167
168
//
168
      public synchronized Object get(Object key)
169
//      public synchronized Object get(Object key)
169
      {
170
//      {
170
        WeakReference reference = (WeakReference)super.get(key);
171
//        WeakReference reference = (WeakReference)super.get(key);
171
        return reference == null ? null : reference.get();
172
//        return reference == null ? null : reference.get();
172
      }
173
//      }
173
         
174
//
174
      public synchronized Object put(Object key, Object value)
175
//      public synchronized Object put(Object key, Object value)
175
      {
176
//      {
176
        super.put(key, new WeakReference(value));
177
//        super.put(key, new WeakReference(value));
177
        if (++count > limit)
178
//        if (++count > limit)
178
        {
179
//        {
179
          cleanGCedValues();
180
//          cleanGCedValues();
180
        }
181
//        }
181
182
//
182
        // The return value is not used.
183
//        // The return value is not used.
183
        return null;
184
//        return null;
184
      }
185
//      }
185
      
186
//
186
      private void cleanGCedValues()
187
//      private void cleanGCedValues()
187
      {
188
//      {
188
        for (Iterator i = entrySet().iterator(); i.hasNext(); )
189
//        for (Iterator i = entrySet().iterator(); i.hasNext(); )
189
        {
190
//        {
190
          Map.Entry entry = (Map.Entry)i.next();
191
//          Map.Entry entry = (Map.Entry)i.next();
191
          WeakReference reference = (WeakReference)entry.getValue();
192
//          WeakReference reference = (WeakReference)entry.getValue();
192
          if (reference.get() == null)
193
//          if (reference.get() == null)
193
          {
194
//          {
194
            i.remove();
195
//            i.remove();
195
          }
196
//          }
196
        }
197
//        }
197
        count = 0;
198
//        count = 0;
198
        limit = Math.max(MIN_LIMIT, size() / 2);
199
//        limit = Math.max(MIN_LIMIT, size() / 2);
199
      }
200
//      }
200
    };
201
//    }
202
  ;
201
203
202
  // The lower-cased schemes that will be used to identify archive URIs.
204
  // The lower-cased schemes that will be used to identify archive URIs.
203
  private static final Set archiveSchemes;
205
  private static final Set archiveSchemes;
Lines 246-252 Link Here
246
  private static final long ALPHANUM_LO = ALPHA_LO | DIGIT_LO;
248
  private static final long ALPHANUM_LO = ALPHA_LO | DIGIT_LO;
247
  private static final long HEX_HI = DIGIT_HI | highBitmask('A', 'F') | highBitmask('a', 'f');
249
  private static final long HEX_HI = DIGIT_HI | highBitmask('A', 'F') | highBitmask('a', 'f');
248
  private static final long HEX_LO = DIGIT_LO | lowBitmask('A', 'F')  | lowBitmask('a', 'f');
250
  private static final long HEX_LO = DIGIT_LO | lowBitmask('A', 'F')  | lowBitmask('a', 'f');
249
  private static final long UNRESERVED_HI = ALPHANUM_HI | highBitmask("-_.!~*'()"); 
251
  private static final long UNRESERVED_HI = ALPHANUM_HI | highBitmask("-_.!~*'()");
250
  private static final long UNRESERVED_LO = ALPHANUM_LO | lowBitmask("-_.!~*'()");
252
  private static final long UNRESERVED_LO = ALPHANUM_LO | lowBitmask("-_.!~*'()");
251
  private static final long RESERVED_HI = highBitmask(";/?:@&=+$,");
253
  private static final long RESERVED_HI = highBitmask(";/?:@&=+$,");
252
  private static final long RESERVED_LO = lowBitmask(";/?:@&=+$,");
254
  private static final long RESERVED_LO = lowBitmask(";/?:@&=+$,");
Lines 254-260 Link Here
254
  private static final long URIC_LO = RESERVED_LO | UNRESERVED_LO;
256
  private static final long URIC_LO = RESERVED_LO | UNRESERVED_LO;
255
257
256
  // Additional useful character classes, including characters valid in certain
258
  // Additional useful character classes, including characters valid in certain
257
  // URI components and separators used in parsing them out of a string. 
259
  // URI components and separators used in parsing them out of a string.
258
  //
260
  //
259
  private static final long SEGMENT_CHAR_HI = UNRESERVED_HI | highBitmask(";:@&=+$,");  // | ucschar | escaped
261
  private static final long SEGMENT_CHAR_HI = UNRESERVED_HI | highBitmask(";:@&=+$,");  // | ucschar | escaped
260
  private static final long SEGMENT_CHAR_LO = UNRESERVED_LO | lowBitmask(";:@&=+$,");
262
  private static final long SEGMENT_CHAR_LO = UNRESERVED_LO | lowBitmask(";:@&=+$,");
Lines 267-284 Link Here
267
  private static final long SEGMENT_END_HI = highBitmask("/?#");
269
  private static final long SEGMENT_END_HI = highBitmask("/?#");
268
  private static final long SEGMENT_END_LO = lowBitmask("/?#");
270
  private static final long SEGMENT_END_LO = lowBitmask("/?#");
269
271
270
  // We can't want to do encoding of platform resource URIs by default yet.   
272
  // We can't want to do encoding of platform resource URIs by default yet.
271
  //
273
  //
272
  private static final boolean ENCODE_PLATFORM_RESOURCE_URIS =
274
  private static final boolean ENCODE_PLATFORM_RESOURCE_URIS =
273
    System.getProperty("org.eclipse.emf.common.util.URI.encodePlatformResourceURIs") != null &&
275
//    System.getProperty("org.eclipse.emf.common.util.URI.encodePlatformResourceURIs") != null &&
274
    !"false".equalsIgnoreCase(System.getProperty("org.eclipse.emf.common.util.URI.encodePlatformResourceURIs"));
276
//    !"false".equalsIgnoreCase(System.getProperty("org.eclipse.emf.common.util.URI.encodePlatformResourceURIs"));
277
	  false;
275
278
276
  // Static initializer for archiveSchemes.
279
  // Static initializer for archiveSchemes.
277
  static
280
  static
278
  {
281
  {
279
    Set set = new HashSet();
282
    Set set = new HashSet();
280
    String propertyValue = System.getProperty("org.eclipse.emf.common.util.URI.archiveSchemes");
283
//    String propertyValue = System.getProperty("org.eclipse.emf.common.util.URI.archiveSchemes");
281
284
    String propertyValue = null;
282
    if (propertyValue == null)
285
    if (propertyValue == null)
283
    {
286
    {
284
      set.add(SCHEME_JAR);
287
      set.add(SCHEME_JAR);
Lines 286-298 Link Here
286
      set.add(SCHEME_ARCHIVE);
289
      set.add(SCHEME_ARCHIVE);
287
    }
290
    }
288
    else
291
    else
289
    { 
292
    {
290
      for (StringTokenizer t = new StringTokenizer(propertyValue); t.hasMoreTokens(); )
293
      for (StringTokenizer t = new StringTokenizer(propertyValue); t.hasMoreTokens(); )
291
      {
294
      {
292
        set.add(t.nextToken().toLowerCase());
295
        set.add(t.nextToken().toLowerCase());
293
      }
296
      }
294
    }
297
    }
295
    
298
296
    archiveSchemes = Collections.unmodifiableSet(set);
299
    archiveSchemes = Collections.unmodifiableSet(set);
297
  }
300
  }
298
301
Lines 449-464 Link Here
449
  /**
452
  /**
450
   * Static factory method for a hierarchical URI with absolute path.
453
   * Static factory method for a hierarchical URI with absolute path.
451
   * The URI will be relative if <code>scheme</code> is non-null, and
454
   * The URI will be relative if <code>scheme</code> is non-null, and
452
   * absolute otherwise. 
455
   * absolute otherwise.
453
   *
456
   *
454
   * @param segments an array of non-null strings, each representing one
457
   * @param segments an array of non-null strings, each representing one
455
   * segment of the path.  As an absolute path, it is automatically
458
   * segment of the path.  As an absolute path, it is automatically
456
   * preceeded by a <code>/</code> separator.  If desired, a trailing
459
   * preceeded by a <code>/</code> separator.  If desired, a trailing
457
   * separator should be represented by an empty-string segment as the last
460
   * separator should be represented by an empty-string segment as the last
458
   * element of the array. 
461
   * element of the array.
459
   *
462
   *
460
   * @exception java.lang.IllegalArgumentException if <code>scheme</code> is
463
   * @exception java.lang.IllegalArgumentException if <code>scheme</code> is
461
   * an <a href="#archive_explanation">archive URI</a> scheme and 
464
   * an <a href="#archive_explanation">archive URI</a> scheme and
462
   * <code>device</code> is non-null, or if <code>scheme</code>,
465
   * <code>device</code> is non-null, or if <code>scheme</code>,
463
   * <code>authority</code>, <code>device</code>, <code>segments</code>,
466
   * <code>authority</code>, <code>device</code>, <code>segments</code>,
464
   * <code>query</code>, or <code>fragment</code> is not valid according to
467
   * <code>query</code>, or <code>fragment</code> is not valid according to
Lines 491-497 Link Here
491
   * empty-string segment at the end of the array.
494
   * empty-string segment at the end of the array.
492
   *
495
   *
493
   * @exception java.lang.IllegalArgumentException if <code>segments</code>,
496
   * @exception java.lang.IllegalArgumentException if <code>segments</code>,
494
   * <code>query</code>, or <code>fragment</code> is not valid according to 
497
   * <code>query</code>, or <code>fragment</code> is not valid according to
495
   * {@link #validSegments validSegments}, {@link #validQuery validQuery}, or
498
   * {@link #validSegments validSegments}, {@link #validQuery validQuery}, or
496
   * {@link #validFragment validFragment}, respectively.
499
   * {@link #validFragment validFragment}, respectively.
497
   */
500
   */
Lines 507-517 Link Here
507
  // immutability.
510
  // immutability.
508
  private static String[] fix(String[] segments)
511
  private static String[] fix(String[] segments)
509
  {
512
  {
510
    return segments == null ? NO_SEGMENTS : (String[])segments.clone();
513
//    return segments == null ? NO_SEGMENTS : (String[])segments.clone();
514
    return segments == null ? NO_SEGMENTS : clone(segments);
511
  }
515
  }
512
  
516
517
  private static String[] clone(String[] s) {
518
	  String[] rv = new String[s.length];
519
	  for( int i = 0; i < s.length; i++ ) {
520
		  rv[i] = s[i];
521
	  }
522
523
	  return rv;
524
  }
525
513
  /**
526
  /**
514
   * Static factory method based on parsing a URI string, with 
527
   * Static factory method based on parsing a URI string, with
515
   * <a href="#device_explanation">explicit device support</a> and handling
528
   * <a href="#device_explanation">explicit device support</a> and handling
516
   * for <a href="#archive_explanation">archive URIs</a> enabled. The
529
   * for <a href="#archive_explanation">archive URIs</a> enabled. The
517
   * specified string is parsed as described in <a
530
   * specified string is parsed as described in <a
Lines 532-538 Link Here
532
   */
545
   */
533
  public static URI createURI(String uri)
546
  public static URI createURI(String uri)
534
  {
547
  {
535
    return createURIWithCache(uri); 
548
    return createURIWithCache(uri);
536
  }
549
  }
537
550
538
  /**
551
  /**
Lines 540-551 Link Here
540
   * Appropriate encoding is performed for each component of the URI.
553
   * Appropriate encoding is performed for each component of the URI.
541
   * If more than one <code>#</code> is in the string, the last one is
554
   * If more than one <code>#</code> is in the string, the last one is
542
   * assumed to be the fragment's separator, and any others are encoded.
555
   * assumed to be the fragment's separator, and any others are encoded.
543
   *  
556
   *
544
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
557
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
545
   * unescaped if they already begin a valid three-character escape sequence;
558
   * unescaped if they already begin a valid three-character escape sequence;
546
   * <code>false</code> to encode all <code>%</code> characters.  Note that
559
   * <code>false</code> to encode all <code>%</code> characters.  Note that
547
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
560
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
548
   * escaped. 
561
   * escaped.
549
   *
562
   *
550
   * @exception java.lang.IllegalArgumentException if any component parsed
563
   * @exception java.lang.IllegalArgumentException if any component parsed
551
   * from <code>uri</code> is not valid according to {@link #validScheme
564
   * from <code>uri</code> is not valid according to {@link #validScheme
Lines 582-601 Link Here
582
   * the fragment separator, and any others should be encoded.
595
   * the fragment separator, and any others should be encoded.
583
   * @see #createURI(String, boolean, int)
596
   * @see #createURI(String, boolean, int)
584
   */
597
   */
585
  public static final int FRAGMENT_LAST_SEPARATOR = 2; 
598
  public static final int FRAGMENT_LAST_SEPARATOR = 2;
586
599
587
  /**
600
  /**
588
   * Static factory method that encodes and parses the given URI string.
601
   * Static factory method that encodes and parses the given URI string.
589
   * Appropriate encoding is performed for each component of the URI.
602
   * Appropriate encoding is performed for each component of the URI.
590
   * Control is provided over which, if any, <code>#</code> should be 
603
   * Control is provided over which, if any, <code>#</code> should be
591
   * taken as the fragment separator and which should be encoded.
604
   * taken as the fragment separator and which should be encoded.
592
   *  
605
   *
593
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
606
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
594
   * unescaped if they already begin a valid three-character escape sequence;
607
   * unescaped if they already begin a valid three-character escape sequence;
595
   * <code>false</code> to encode all <code>%</code> characters.  Note that
608
   * <code>false</code> to encode all <code>%</code> characters.  Note that
596
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
609
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
597
   * escaped. 
610
   * escaped.
598
   * 
611
   *
599
   * @param fragmentLocationStyle one of {@link #FRAGMENT_NONE},
612
   * @param fragmentLocationStyle one of {@link #FRAGMENT_NONE},
600
   * {@link #FRAGMENT_FIRST_SEPARATOR}, or {@link #FRAGMENT_LAST_SEPARATOR},
613
   * {@link #FRAGMENT_FIRST_SEPARATOR}, or {@link #FRAGMENT_LAST_SEPARATOR},
601
   * indicating which, if any, of the <code>#</code> characters should be
614
   * indicating which, if any, of the <code>#</code> characters should be
Lines 615-622 Link Here
615
  }
628
  }
616
629
617
  /**
630
  /**
618
   * Static factory method based on parsing a URI string, with 
631
   * Static factory method based on parsing a URI string, with
619
   * <a href="#device_explanation">explicit device support</a> enabled.  
632
   * <a href="#device_explanation">explicit device support</a> enabled.
620
   * Note that validity testing is not a strict as in the RFC; essentially,
633
   * Note that validity testing is not a strict as in the RFC; essentially,
621
   * only separator characters are considered.  So, for example, non-Latin
634
   * only separator characters are considered.  So, for example, non-Latin
622
   * alphabet characters appearing in the scheme would not be considered an
635
   * alphabet characters appearing in the scheme would not be considered an
Lines 647-653 Link Here
647
  // by string-parsing factory methods, instead of parseIntoURI() directly.
660
  // by string-parsing factory methods, instead of parseIntoURI() directly.
648
  /**
661
  /**
649
   * This method was included in the public API by mistake.
662
   * This method was included in the public API by mistake.
650
   * 
663
   *
651
   * @deprecated Please use {@link #createURI createURI} instead.
664
   * @deprecated Please use {@link #createURI createURI} instead.
652
   */
665
   */
653
  public static URI createURIWithCache(String uri)
666
  public static URI createURIWithCache(String uri)
Lines 725-731 Link Here
725
    {
738
    {
726
      j = find(uri, i + 1, SEGMENT_END_HI, SEGMENT_END_LO);
739
      j = find(uri, i + 1, SEGMENT_END_HI, SEGMENT_END_LO);
727
      String s = uri.substring(i + 1, j);
740
      String s = uri.substring(i + 1, j);
728
      
741
729
      if (s.length() > 0 && s.charAt(s.length() - 1) == DEVICE_IDENTIFIER)
742
      if (s.length() > 0 && s.charAt(s.length() - 1) == DEVICE_IDENTIFIER)
730
      {
743
      {
731
        device = s;
744
        device = s;
Lines 817-823 Link Here
817
   *
830
   *
818
   * <p>A relative path with a specified device (something like
831
   * <p>A relative path with a specified device (something like
819
   * <code>C:myfile.txt</code>) cannot be expressed as a valid URI.
832
   * <code>C:myfile.txt</code>) cannot be expressed as a valid URI.
820
   * 
833
   *
821
   * @exception java.lang.IllegalArgumentException if <code>pathName</code>
834
   * @exception java.lang.IllegalArgumentException if <code>pathName</code>
822
   * specifies a device and a relative path, or if any component of the path
835
   * specifies a device and a relative path, or if any component of the path
823
   * is not valid according to {@link #validAuthority validAuthority}, {@link
836
   * is not valid according to {@link #validAuthority validAuthority}, {@link
Lines 826-840 Link Here
826
   */
839
   */
827
  public static URI createFileURI(String pathName)
840
  public static URI createFileURI(String pathName)
828
  {
841
  {
829
    File file = new File(pathName);
842
//    File file = new File(pathName);
830
    String uri = File.separatorChar != '/' ? pathName.replace(File.separatorChar, SEGMENT_SEPARATOR) : pathName;
843
    String uri = File_separatorChar != '/' ? pathName.replace(File_separatorChar, SEGMENT_SEPARATOR) : pathName;
831
    uri = encode(uri, PATH_CHAR_HI, PATH_CHAR_LO, false);
844
    uri = encode(uri, PATH_CHAR_HI, PATH_CHAR_LO, false);
832
    if (file.isAbsolute())
845
//    if (file.isAbsolute())
833
    {
846
//    {
834
      URI result = createURI((uri.charAt(0) == SEGMENT_SEPARATOR ? "file:" : "file:/") + uri);
847
//      URI result = createURI((uri.charAt(0) == SEGMENT_SEPARATOR ? "file:" : "file:/") + uri);
835
      return result;
848
//      return result;
836
    }
849
//    }
837
    else
850
//    else
838
    {
851
    {
839
      URI result = createURI(uri);
852
      URI result = createURI(uri);
840
      if (result.scheme() != null)
853
      if (result.scheme() != null)
Lines 863-872 Link Here
863
   * stand-alone EMF.
876
   * stand-alone EMF.
864
   *
877
   *
865
   * <p>Path encoding is performed only if the
878
   * <p>Path encoding is performed only if the
866
   * <code>org.eclipse.emf.common.util.URI.encodePlatformResourceURIs</code> 
879
   * <code>org.eclipse.emf.common.util.URI.encodePlatformResourceURIs</code>
867
   * system property is set to "true". Decoding can be performed with the
880
   * system property is set to "true". Decoding can be performed with the
868
   * static {@link #decode(String) decode} method.
881
   * static {@link #decode(String) decode} method.
869
   * 
882
   *
870
   * @exception java.lang.IllegalArgumentException if any component parsed
883
   * @exception java.lang.IllegalArgumentException if any component parsed
871
   * from the path is not valid according to {@link #validDevice validDevice},
884
   * from the path is not valid according to {@link #validDevice validDevice},
872
   * {@link #validSegments validSegments}, {@link #validQuery validQuery}, or
885
   * {@link #validSegments validSegments}, {@link #validQuery validQuery}, or
Lines 903-909 Link Here
903
   * and other characters disallowed in URIs, as well as <code>?</code>,
916
   * and other characters disallowed in URIs, as well as <code>?</code>,
904
   * which would delimit a path from a query.  Decoding can be performed with
917
   * which would delimit a path from a query.  Decoding can be performed with
905
   * the static {@link #decode(String) decode} method.
918
   * the static {@link #decode(String) decode} method.
906
   * 
919
   *
907
   * @exception java.lang.IllegalArgumentException if any component parsed
920
   * @exception java.lang.IllegalArgumentException if any component parsed
908
   * from the path is not valid according to {@link #validDevice validDevice},
921
   * from the path is not valid according to {@link #validDevice validDevice},
909
   * {@link #validSegments validSegments}, {@link #validQuery validQuery}, or
922
   * {@link #validSegments validSegments}, {@link #validQuery validQuery}, or
Lines 913-921 Link Here
913
   */
926
   */
914
  public static URI createPlatformResourceURI(String pathName, boolean encode)
927
  public static URI createPlatformResourceURI(String pathName, boolean encode)
915
  {
928
  {
916
    if (File.separatorChar != SEGMENT_SEPARATOR)
929
    if (File_separatorChar != SEGMENT_SEPARATOR)
917
    {
930
    {
918
      pathName = pathName.replace(File.separatorChar, SEGMENT_SEPARATOR);
931
      pathName = pathName.replace(File_separatorChar, SEGMENT_SEPARATOR);
919
    }
932
    }
920
933
921
    if (encode)
934
    if (encode)
Lines 925-931 Link Here
925
    URI result = createURI((pathName.charAt(0) == SEGMENT_SEPARATOR ? "platform:/resource" : "platform:/resource/") + pathName);
938
    URI result = createURI((pathName.charAt(0) == SEGMENT_SEPARATOR ? "platform:/resource" : "platform:/resource/") + pathName);
926
    return result;
939
    return result;
927
  }
940
  }
928
  
941
929
  // Private constructor for use of static factory methods.
942
  // Private constructor for use of static factory methods.
930
  private URI(boolean hierarchical, String scheme, String authority,
943
  private URI(boolean hierarchical, String scheme, String authority,
931
              String device, boolean absolutePath, String[] segments,
944
              String device, boolean absolutePath, String[] segments,
Lines 976-982 Link Here
976
    this.hashCode = hashCode;
989
    this.hashCode = hashCode;
977
    //this.iri = iri;
990
    //this.iri = iri;
978
    this.hierarchical = hierarchical;
991
    this.hierarchical = hierarchical;
979
    this.scheme = scheme == null ? null : scheme.intern();
992
    this.scheme = scheme == null ? null : new String(scheme);
980
    this.authority = authority;
993
    this.authority = authority;
981
    this.device = device;
994
    this.device = device;
982
    this.absolutePath = absolutePath;
995
    this.absolutePath = absolutePath;
Lines 984-990 Link Here
984
    this.query = query;
997
    this.query = query;
985
    this.fragment = fragment;
998
    this.fragment = fragment;
986
  }
999
  }
987
  
1000
988
  // Validates all of the URI components.  Factory methods should call this
1001
  // Validates all of the URI components.  Factory methods should call this
989
  // before using the constructor, though they must ensure that the
1002
  // before using the constructor, though they must ensure that the
990
  // inter-component requirements described in their own Javadocs are all
1003
  // inter-component requirements described in their own Javadocs are all
Lines 1044-1050 Link Here
1044
   */
1057
   */
1045
  public static boolean validScheme(String value)
1058
  public static boolean validScheme(String value)
1046
  {
1059
  {
1047
    return value == null || !contains(value, MAJOR_SEPARATOR_HI, MAJOR_SEPARATOR_LO);  
1060
    return value == null || !contains(value, MAJOR_SEPARATOR_HI, MAJOR_SEPARATOR_LO);
1048
1061
1049
  // <p>A valid scheme may be null, or consist of a single letter followed
1062
  // <p>A valid scheme may be null, or consist of a single letter followed
1050
  // by any number of letters, numbers, and the following characters:
1063
  // by any number of letters, numbers, and the following characters:
Lines 1072-1078 Link Here
1072
1085
1073
  // <p>A valid opaque part must be non-null and non-empty. It may contain
1086
  // <p>A valid opaque part must be non-null and non-empty. It may contain
1074
  // any allowed URI characters, but its first character may not be
1087
  // any allowed URI characters, but its first character may not be
1075
  // <code>/</code> 
1088
  // <code>/</code>
1076
1089
1077
    //return value != null && value.length() != 0 &&
1090
    //return value != null && value.length() != 0 &&
1078
    //  value.charAt(0) != SEGMENT_SEPARATOR &&
1091
    //  value.charAt(0) != SEGMENT_SEPARATOR &&
Lines 1128-1134 Link Here
1128
   * URI</a>. This method has been replaced by {@link #validArchiveAuthority
1141
   * URI</a>. This method has been replaced by {@link #validArchiveAuthority
1129
   * validArchiveAuthority} since the same form of URI is now supported
1142
   * validArchiveAuthority} since the same form of URI is now supported
1130
   * for schemes other than "jar". This now simply calls that method.
1143
   * for schemes other than "jar". This now simply calls that method.
1131
   * 
1144
   *
1132
   * @deprecated As of EMF 2.0, replaced by {@link #validArchiveAuthority
1145
   * @deprecated As of EMF 2.0, replaced by {@link #validArchiveAuthority
1133
   * validArchiveAuthority}.
1146
   * validArchiveAuthority}.
1134
   */
1147
   */
Lines 1146-1152 Link Here
1146
   * character must be <code>:</code>
1159
   * character must be <code>:</code>
1147
   */
1160
   */
1148
  public static boolean validDevice(String value)
1161
  public static boolean validDevice(String value)
1149
  {    
1162
  {
1150
    if (value == null) return true;
1163
    if (value == null) return true;
1151
    int len = value.length();
1164
    int len = value.length();
1152
    return len > 0 && value.charAt(len - 1) == DEVICE_IDENTIFIER &&
1165
    return len > 0 && value.charAt(len - 1) == DEVICE_IDENTIFIER &&
Lines 1174-1180 Link Here
1174
    return value != null && !contains(value, SEGMENT_END_HI, SEGMENT_END_LO);
1187
    return value != null && !contains(value, SEGMENT_END_HI, SEGMENT_END_LO);
1175
1188
1176
  // <p>A valid path segment must be non-null and may contain any allowed URI
1189
  // <p>A valid path segment must be non-null and may contain any allowed URI
1177
  // characters except for the following: <code>/ ?</code> 
1190
  // characters except for the following: <code>/ ?</code>
1178
1191
1179
    //return value != null && validate(value, SEGMENT_CHAR_HI, SEGMENT_CHAR_LO, true, true);
1192
    //return value != null && validate(value, SEGMENT_CHAR_HI, SEGMENT_CHAR_LO, true, true);
1180
  }
1193
  }
Lines 1198-1204 Link Here
1198
1211
1199
  // Returns null if the specicied value is null or would be a valid path
1212
  // Returns null if the specicied value is null or would be a valid path
1200
  // segment array of a URI; otherwise, the value of the first invalid
1213
  // segment array of a URI; otherwise, the value of the first invalid
1201
  // segment. 
1214
  // segment.
1202
  private static String firstInvalidSegment(String[] value)
1215
  private static String firstInvalidSegment(String[] value)
1203
  {
1216
  {
1204
    if (value == null) return null;
1217
    if (value == null) return null;
Lines 1262-1268 Link Here
1262
                                     boolean allowNonASCII, boolean allowEscaped)
1275
                                     boolean allowNonASCII, boolean allowEscaped)
1263
  {
1276
  {
1264
    for (int i = 0, len = value.length(); i < len; i++)
1277
    for (int i = 0, len = value.length(); i < len; i++)
1265
    { 
1278
    {
1266
      char c = value.charAt(i);
1279
      char c = value.charAt(i);
1267
1280
1268
      if (matches(c, highBitmask, lowBitmask)) continue;
1281
      if (matches(c, highBitmask, lowBitmask)) continue;
Lines 1298-1304 Link Here
1298
1311
1299
  /**
1312
  /**
1300
   * Returns <code>true</code> if this is a hierarcical URI with an authority
1313
   * Returns <code>true</code> if this is a hierarcical URI with an authority
1301
   * component; <code>false</code> otherwise. 
1314
   * component; <code>false</code> otherwise.
1302
   */
1315
   */
1303
  public boolean hasAuthority()
1316
  public boolean hasAuthority()
1304
  {
1317
  {
Lines 1361-1367 Link Here
1361
1374
1362
  /**
1375
  /**
1363
   * Returns <code>true</code> if this is a hierarchical URI with an empty
1376
   * Returns <code>true</code> if this is a hierarchical URI with an empty
1364
   * relative path; <code>false</code> otherwise.  
1377
   * relative path; <code>false</code> otherwise.
1365
   *
1378
   *
1366
   * <p>Note that <code>!hasEmpty()</code> does <em>not</em> imply that this
1379
   * <p>Note that <code>!hasEmpty()</code> does <em>not</em> imply that this
1367
   * URI has any path segments; however, <code>hasRelativePath &&
1380
   * URI has any path segments; however, <code>hasRelativePath &&
Lines 1458-1464 Link Here
1458
    // By default, "jar", "zip", and "archive" are considered archives.
1471
    // By default, "jar", "zip", and "archive" are considered archives.
1459
    return value != null && archiveSchemes.contains(value.toLowerCase());
1472
    return value != null && archiveSchemes.contains(value.toLowerCase());
1460
  }
1473
  }
1461
  
1474
1462
  /**
1475
  /**
1463
   * Returns the hash code.
1476
   * Returns the hash code.
1464
   */
1477
   */
Lines 1487-1493 Link Here
1487
      equals(scheme, uri.scheme(), true) &&
1500
      equals(scheme, uri.scheme(), true) &&
1488
      equals(authority, hierarchical ? uri.authority() : uri.opaquePart()) &&
1501
      equals(authority, hierarchical ? uri.authority() : uri.opaquePart()) &&
1489
      equals(device, uri.device()) &&
1502
      equals(device, uri.device()) &&
1490
      equals(query, uri.query()) && 
1503
      equals(query, uri.query()) &&
1491
      equals(fragment, uri.fragment()) &&
1504
      equals(fragment, uri.fragment()) &&
1492
      segmentsEqual(uri);
1505
      segmentsEqual(uri);
1493
  }
1506
  }
Lines 1551-1559 Link Here
1551
   * user info portion, returns it; <code>null</code> otherwise.
1564
   * user info portion, returns it; <code>null</code> otherwise.
1552
   */
1565
   */
1553
  public String userInfo()
1566
  public String userInfo()
1554
  { 
1567
  {
1555
    if (!hasAuthority()) return null;
1568
    if (!hasAuthority()) return null;
1556
   
1569
1557
    int i = authority.indexOf(USER_INFO_SEPARATOR);
1570
    int i = authority.indexOf(USER_INFO_SEPARATOR);
1558
    return i < 0 ? null : authority.substring(0, i);
1571
    return i < 0 ? null : authority.substring(0, i);
1559
  }
1572
  }
Lines 1565-1571 Link Here
1565
  public String host()
1578
  public String host()
1566
  {
1579
  {
1567
    if (!hasAuthority()) return null;
1580
    if (!hasAuthority()) return null;
1568
    
1581
1569
    int i = authority.indexOf(USER_INFO_SEPARATOR);
1582
    int i = authority.indexOf(USER_INFO_SEPARATOR);
1570
    int j = authority.indexOf(PORT_SEPARATOR);
1583
    int j = authority.indexOf(PORT_SEPARATOR);
1571
    return j < 0 ? authority.substring(i + 1) : authority.substring(i + 1, j);
1584
    return j < 0 ? authority.substring(i + 1) : authority.substring(i + 1, j);
Lines 1601-1607 Link Here
1601
   */
1614
   */
1602
  public String[] segments()
1615
  public String[] segments()
1603
  {
1616
  {
1604
    return (String[])segments.clone();
1617
	  return clone(segments);
1605
  }
1618
  }
1606
1619
1607
  /**
1620
  /**
Lines 1669-1677 Link Here
1669
1682
1670
  /**
1683
  /**
1671
   * If this is a hierarchical URI with a path, returns a string
1684
   * If this is a hierarchical URI with a path, returns a string
1672
   * representation of the path, including the authority and the 
1685
   * representation of the path, including the authority and the
1673
   * <a href="#device_explanation">device component</a>; 
1686
   * <a href="#device_explanation">device component</a>;
1674
   * <code>null</code> otherwise.  
1687
   * <code>null</code> otherwise.
1675
   *
1688
   *
1676
   * <p>If there is no authority, the format of this string is:
1689
   * <p>If there is no authority, the format of this string is:
1677
   * <pre>
1690
   * <pre>
Lines 1734-1740 Link Here
1734
      throw new IllegalArgumentException(
1747
      throw new IllegalArgumentException(
1735
        "invalid query portion: " + query);
1748
        "invalid query portion: " + query);
1736
    }
1749
    }
1737
    return new URI(hierarchical, scheme, authority, device, absolutePath, segments, query, fragment); 
1750
    return new URI(hierarchical, scheme, authority, device, absolutePath, segments, query, fragment);
1738
  }
1751
  }
1739
1752
1740
  /**
1753
  /**
Lines 1749-1755 Link Here
1749
    }
1762
    }
1750
    else
1763
    else
1751
    {
1764
    {
1752
      return new URI(hierarchical, scheme, authority, device, absolutePath, segments, null, fragment); 
1765
      return new URI(hierarchical, scheme, authority, device, absolutePath, segments, null, fragment);
1753
    }
1766
    }
1754
  }
1767
  }
1755
1768
Lines 1776-1782 Link Here
1776
      throw new IllegalArgumentException(
1789
      throw new IllegalArgumentException(
1777
        "invalid fragment portion: " + fragment);
1790
        "invalid fragment portion: " + fragment);
1778
    }
1791
    }
1779
    URI result = new URI(hierarchical, scheme, authority, device, absolutePath, segments, query, fragment); 
1792
    URI result = new URI(hierarchical, scheme, authority, device, absolutePath, segments, query, fragment);
1780
1793
1781
    if (!hasFragment())
1794
    if (!hasFragment())
1782
    {
1795
    {
Lines 1797-1803 Link Here
1797
    }
1810
    }
1798
    else if (cachedTrimFragment == null)
1811
    else if (cachedTrimFragment == null)
1799
    {
1812
    {
1800
      cachedTrimFragment = new URI(hierarchical, scheme, authority, device, absolutePath, segments, query, null); 
1813
      cachedTrimFragment = new URI(hierarchical, scheme, authority, device, absolutePath, segments, query, null);
1801
    }
1814
    }
1802
1815
1803
    return cachedTrimFragment;
1816
    return cachedTrimFragment;
Lines 1866-1872 Link Here
1866
    String newQuery = query;
1879
    String newQuery = query;
1867
    // note: it's okay for two URIs to share a segments array, since
1880
    // note: it's okay for two URIs to share a segments array, since
1868
    // neither will ever modify it
1881
    // neither will ever modify it
1869
    
1882
1870
    if (authority == null)
1883
    if (authority == null)
1871
    {
1884
    {
1872
      // no authority: use base's
1885
      // no authority: use base's
Lines 1888-1894 Link Here
1888
        {
1901
        {
1889
          // relative path: merge with base and keep query (note: if the
1902
          // relative path: merge with base and keep query (note: if the
1890
          // base has no path and this a non-empty relative path, there is
1903
          // base has no path and this a non-empty relative path, there is
1891
          // an implied root in the resulting path) 
1904
          // an implied root in the resulting path)
1892
          newAbsolutePath = base.hasAbsolutePath() || !hasEmptyPath();
1905
          newAbsolutePath = base.hasAbsolutePath() || !hasEmptyPath();
1893
          newSegments = newAbsolutePath ? mergePath(base, preserveRootParents)
1906
          newSegments = newAbsolutePath ? mergePath(base, preserveRootParents)
1894
            : NO_SEGMENTS;
1907
            : NO_SEGMENTS;
Lines 1898-1904 Link Here
1898
      // else keep device, path, and query
1911
      // else keep device, path, and query
1899
    }
1912
    }
1900
    // else keep authority, device, path, and query
1913
    // else keep authority, device, path, and query
1901
    
1914
1902
    // always keep fragment, even if null, and use scheme from base;
1915
    // always keep fragment, even if null, and use scheme from base;
1903
    // no validation needed since all components are from existing URIs
1916
    // no validation needed since all components are from existing URIs
1904
    return new URI(true, base.scheme(), newAuthority, newDevice,
1917
    return new URI(true, base.scheme(), newAuthority, newDevice,
Lines 1937-1943 Link Here
1937
      sp = accumulate(stack, sp, segments[i], preserveRootParents);
1950
      sp = accumulate(stack, sp, segments[i], preserveRootParents);
1938
    }
1951
    }
1939
1952
1940
    // if the relative path is empty or ends in an empty segment, a parent 
1953
    // if the relative path is empty or ends in an empty segment, a parent
1941
    // reference, or a self referenfce, add a trailing separator to a
1954
    // reference, or a self referenfce, add a trailing separator to a
1942
    // non-empty path
1955
    // non-empty path
1943
    if (sp > 0 &&  (segmentCount == 0 ||
1956
    if (sp > 0 &&  (segmentCount == 0 ||
Lines 1986-1992 Link Here
1986
  /**
1999
  /**
1987
   * Finds the shortest relative or, if necessary, the absolute URI that,
2000
   * Finds the shortest relative or, if necessary, the absolute URI that,
1988
   * when resolved against the given <code>base</code> absolute hierarchical
2001
   * when resolved against the given <code>base</code> absolute hierarchical
1989
   * URI using {@link #resolve(URI) resolve}, will yield this absolute URI.  
2002
   * URI using {@link #resolve(URI) resolve}, will yield this absolute URI.
1990
   *
2003
   *
1991
   * @exception java.lang.IllegalArgumentException if <code>base</code> is
2004
   * @exception java.lang.IllegalArgumentException if <code>base</code> is
1992
   * non-hierarchical or is relative.
2005
   * non-hierarchical or is relative.
Lines 2034-2040 Link Here
2034
2047
2035
    // note: these assertions imply that neither this nor the base URI has a
2048
    // note: these assertions imply that neither this nor the base URI has a
2036
    // relative path; thus, both have either an absolute path or no path
2049
    // relative path; thus, both have either an absolute path or no path
2037
    
2050
2038
    // different scheme: need complete, absolute URI
2051
    // different scheme: need complete, absolute URI
2039
    if (!scheme.equalsIgnoreCase(base.scheme())) return this;
2052
    if (!scheme.equalsIgnoreCase(base.scheme())) return this;
2040
2053
Lines 2224-2230 Link Here
2224
    if (sp > 0 && (SEGMENT_EMPTY.equals(segments[segmentCount - 1]) ||
2237
    if (sp > 0 && (SEGMENT_EMPTY.equals(segments[segmentCount - 1]) ||
2225
                   SEGMENT_PARENT.equals(segments[segmentCount - 1]) ||
2238
                   SEGMENT_PARENT.equals(segments[segmentCount - 1]) ||
2226
                   SEGMENT_SELF.equals(segments[segmentCount - 1])))
2239
                   SEGMENT_SELF.equals(segments[segmentCount - 1])))
2227
    {                   
2240
    {
2228
      stack[sp++] = SEGMENT_EMPTY;
2241
      stack[sp++] = SEGMENT_EMPTY;
2229
    }
2242
    }
2230
2243
Lines 2239-2245 Link Here
2239
   * non-hierarchical URI, this looks like:
2252
   * non-hierarchical URI, this looks like:
2240
   * <pre>
2253
   * <pre>
2241
   *   scheme:opaquePart#fragment</pre>
2254
   *   scheme:opaquePart#fragment</pre>
2242
   * 
2255
   *
2243
   * <p>For a hierarchical URI, it looks like:
2256
   * <p>For a hierarchical URI, it looks like:
2244
   * <pre>
2257
   * <pre>
2245
   *   scheme://authority/device/pathSegment1/pathSegment2...?query#fragment</pre>
2258
   *   scheme://authority/device/pathSegment1/pathSegment2...?query#fragment</pre>
Lines 2335-2341 Link Here
2335
2348
2336
  /**
2349
  /**
2337
   * If this URI may refer directly to a locally accessible file, as
2350
   * If this URI may refer directly to a locally accessible file, as
2338
   * determined by {@link #isFile isFile}, {@link decode decodes} and formats  
2351
   * determined by {@link #isFile isFile}, {@link decode decodes} and formats
2339
   * the URI as a pathname to that file; returns null otherwise.
2352
   * the URI as a pathname to that file; returns null otherwise.
2340
   *
2353
   *
2341
   * <p>If there is no authority, the format of this string is:
2354
   * <p>If there is no authority, the format of this string is:
Lines 2345-2351 Link Here
2345
   * <p>If there is an authority, it is:
2358
   * <p>If there is an authority, it is:
2346
   * <pre>
2359
   * <pre>
2347
   *   //authority/device/pathSegment1/pathSegment2...</pre>
2360
   *   //authority/device/pathSegment1/pathSegment2...</pre>
2348
   * 
2361
   *
2349
   * <p>However, the character used as a separator is system-dependant and
2362
   * <p>However, the character used as a separator is system-dependant and
2350
   * obtained from {@link java.io.File#separatorChar}.
2363
   * obtained from {@link java.io.File#separatorChar}.
2351
   */
2364
   */
Lines 2354-2360 Link Here
2354
    if (!isFile()) return null;
2367
    if (!isFile()) return null;
2355
2368
2356
    StringBuffer result = new StringBuffer();
2369
    StringBuffer result = new StringBuffer();
2357
    char separator = File.separatorChar;
2370
    char separator = File_separatorChar;
2358
2371
2359
    if (hasAuthority())
2372
    if (hasAuthority())
2360
    {
2373
    {
Lines 2433-2446 Link Here
2433
    if (!isHierarchical()) return this;
2446
    if (!isHierarchical()) return this;
2434
2447
2435
    // absolute path or no path -> absolute path
2448
    // absolute path or no path -> absolute path
2436
    boolean newAbsolutePath = !hasRelativePath(); 
2449
    boolean newAbsolutePath = !hasRelativePath();
2437
2450
2438
    int len = this.segments.length;
2451
    int len = this.segments.length;
2439
    int segmentsCount = segments.length;
2452
    int segmentsCount = segments.length;
2440
    String[] newSegments = new String[len + segmentsCount];
2453
    String[] newSegments = new String[len + segmentsCount];
2441
    System.arraycopy(this.segments, 0, newSegments, 0, len);
2454
    System.arraycopy(this.segments, 0, newSegments, 0, len);
2442
    System.arraycopy(segments, 0, newSegments, len, segmentsCount);
2455
    System.arraycopy(segments, 0, newSegments, len, segmentsCount);
2443
    
2456
2444
    return new URI(true, scheme, authority, device, newAbsolutePath,
2457
    return new URI(true, scheme, authority, device, newAbsolutePath,
2445
                   newSegments, query, fragment);
2458
                   newSegments, query, fragment);
2446
  }
2459
  }
Lines 2453-2463 Link Here
2453
   *
2466
   *
2454
   * <p>Note that if all segments are trimmed from an absolute path, the
2467
   * <p>Note that if all segments are trimmed from an absolute path, the
2455
   * root absolute path remains.
2468
   * root absolute path remains.
2456
   * 
2469
   *
2457
   * @param i the number of segments to be trimmed in the returned URI.  If
2470
   * @param i the number of segments to be trimmed in the returned URI.  If
2458
   * less than 1, this URI is returned unchanged; if equal to or greater
2471
   * less than 1, this URI is returned unchanged; if equal to or greater
2459
   * than the number of segments in this URI's path, all segments are
2472
   * than the number of segments in this URI's path, all segments are
2460
   * trimmed.  
2473
   * trimmed.
2461
   */
2474
   */
2462
  public URI trimSegments(int i)
2475
  public URI trimSegments(int i)
2463
  {
2476
  {
Lines 2484-2490 Link Here
2484
   */
2497
   */
2485
  public boolean hasTrailingPathSeparator()
2498
  public boolean hasTrailingPathSeparator()
2486
  {
2499
  {
2487
    return segments.length > 0 && 
2500
    return segments.length > 0 &&
2488
      SEGMENT_EMPTY.equals(segments[segments.length - 1]);
2501
      SEGMENT_EMPTY.equals(segments[segments.length - 1]);
2489
  }
2502
  }
2490
2503
Lines 2540-2549 Link Here
2540
    String[] newSegments = new String[len];
2553
    String[] newSegments = new String[len];
2541
    System.arraycopy(segments, 0, newSegments, 0, len - 1);
2554
    System.arraycopy(segments, 0, newSegments, 0, len - 1);
2542
    newSegments[len - 1] = newLastSegment.toString();
2555
    newSegments[len - 1] = newLastSegment.toString();
2543
    
2556
2544
    // note: segments.length > 0 -> hierarchical
2557
    // note: segments.length > 0 -> hierarchical
2545
    return new URI(true, scheme, authority, device, absolutePath,
2558
    return new URI(true, scheme, authority, device, absolutePath,
2546
                   newSegments, query, fragment); 
2559
                   newSegments, query, fragment);
2547
  }
2560
  }
2548
2561
2549
  /**
2562
  /**
Lines 2566-2572 Link Here
2566
2579
2567
    // note: segments.length > 0 -> hierarchical
2580
    // note: segments.length > 0 -> hierarchical
2568
    return new URI(true, scheme, authority, device, absolutePath,
2581
    return new URI(true, scheme, authority, device, absolutePath,
2569
                   newSegments, query, fragment); 
2582
                   newSegments, query, fragment);
2570
  }
2583
  }
2571
2584
2572
  /**
2585
  /**
Lines 2674-2680 Link Here
2674
    {
2687
    {
2675
      return NO_SEGMENTS;
2688
      return NO_SEGMENTS;
2676
    }
2689
    }
2677
    
2690
2678
    // Otherwise, the path needs only the remaining segments.
2691
    // Otherwise, the path needs only the remaining segments.
2679
    String[] newSegments = new String[segments.length - i];
2692
    String[] newSegments = new String[segments.length - i];
2680
    System.arraycopy(segments, i, newSegments, 0, newSegments.length);
2693
    System.arraycopy(segments, i, newSegments, 0, newSegments.length);
Lines 2685-2696 Link Here
2685
   * Encodes a string so as to produce a valid opaque part value, as defined
2698
   * Encodes a string so as to produce a valid opaque part value, as defined
2686
   * by the RFC.  All excluded characters, such as space and <code>#</code>,
2699
   * by the RFC.  All excluded characters, such as space and <code>#</code>,
2687
   * are escaped, as is <code>/</code> if it is the first character.
2700
   * are escaped, as is <code>/</code> if it is the first character.
2688
   * 
2701
   *
2689
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2702
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2690
   * unescaped if they already begin a valid three-character escape sequence;
2703
   * unescaped if they already begin a valid three-character escape sequence;
2691
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2704
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2692
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2705
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2693
   * escaped. 
2706
   * escaped.
2694
   */
2707
   */
2695
  public static String encodeOpaquePart(String value, boolean ignoreEscaped)
2708
  public static String encodeOpaquePart(String value, boolean ignoreEscaped)
2696
  {
2709
  {
Lines 2704-2715 Link Here
2704
   * Encodes a string so as to produce a valid authority, as defined by the
2717
   * Encodes a string so as to produce a valid authority, as defined by the
2705
   * RFC.  All excluded characters, such as space and <code>#</code>,
2718
   * RFC.  All excluded characters, such as space and <code>#</code>,
2706
   * are escaped, as are <code>/</code> and <code>?</code>
2719
   * are escaped, as are <code>/</code> and <code>?</code>
2707
   * 
2720
   *
2708
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2721
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2709
   * unescaped if they already begin a valid three-character escape sequence;
2722
   * unescaped if they already begin a valid three-character escape sequence;
2710
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2723
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2711
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2724
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2712
   * escaped. 
2725
   * escaped.
2713
   */
2726
   */
2714
  public static String encodeAuthority(String value, boolean ignoreEscaped)
2727
  public static String encodeAuthority(String value, boolean ignoreEscaped)
2715
  {
2728
  {
Lines 2720-2731 Link Here
2720
   * Encodes a string so as to produce a valid segment, as defined by the
2733
   * Encodes a string so as to produce a valid segment, as defined by the
2721
   * RFC.  All excluded characters, such as space and <code>#</code>,
2734
   * RFC.  All excluded characters, such as space and <code>#</code>,
2722
   * are escaped, as are <code>/</code> and <code>?</code>
2735
   * are escaped, as are <code>/</code> and <code>?</code>
2723
   * 
2736
   *
2724
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2737
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2725
   * unescaped if they already begin a valid three-character escape sequence;
2738
   * unescaped if they already begin a valid three-character escape sequence;
2726
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2739
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2727
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2740
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2728
   * escaped. 
2741
   * escaped.
2729
   */
2742
   */
2730
  public static String encodeSegment(String value, boolean ignoreEscaped)
2743
  public static String encodeSegment(String value, boolean ignoreEscaped)
2731
  {
2744
  {
Lines 2735-2746 Link Here
2735
  /**
2748
  /**
2736
   * Encodes a string so as to produce a valid query, as defined by the RFC.
2749
   * Encodes a string so as to produce a valid query, as defined by the RFC.
2737
   * Only excluded characters, such as space and <code>#</code>, are escaped.
2750
   * Only excluded characters, such as space and <code>#</code>, are escaped.
2738
   * 
2751
   *
2739
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2752
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2740
   * unescaped if they already begin a valid three-character escape sequence;
2753
   * unescaped if they already begin a valid three-character escape sequence;
2741
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2754
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2742
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2755
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2743
   * escaped. 
2756
   * escaped.
2744
   */
2757
   */
2745
  public static String encodeQuery(String value, boolean ignoreEscaped)
2758
  public static String encodeQuery(String value, boolean ignoreEscaped)
2746
  {
2759
  {
Lines 2751-2762 Link Here
2751
   * Encodes a string so as to produce a valid fragment, as defined by the
2764
   * Encodes a string so as to produce a valid fragment, as defined by the
2752
   * RFC.  Only excluded characters, such as space and <code>#</code>, are
2765
   * RFC.  Only excluded characters, such as space and <code>#</code>, are
2753
   * escaped.
2766
   * escaped.
2754
   * 
2767
   *
2755
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2768
   * @param ignoreEscaped <code>true</code> to leave <code>%</code> characters
2756
   * unescaped if they already begin a valid three-character escape sequence;
2769
   * unescaped if they already begin a valid three-character escape sequence;
2757
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2770
   * <code>false</code> to encode all <code>%</code> characters.  Note that
2758
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2771
   * if a <code>%</code> is not followed by 2 hex digits, it will always be
2759
   * escaped. 
2772
   * escaped.
2760
   */
2773
   */
2761
  public static String encodeFragment(String value, boolean ignoreEscaped)
2774
  public static String encodeFragment(String value, boolean ignoreEscaped)
2762
  {
2775
  {
Lines 2779-2785 Link Here
2779
      result.append(scheme);
2792
      result.append(scheme);
2780
      result.append(SCHEME_SEPARATOR);
2793
      result.append(SCHEME_SEPARATOR);
2781
    }
2794
    }
2782
    
2795
2783
    int j =
2796
    int j =
2784
      fragmentLocationStyle == FRAGMENT_FIRST_SEPARATOR ? uri.indexOf(FRAGMENT_SEPARATOR) :
2797
      fragmentLocationStyle == FRAGMENT_FIRST_SEPARATOR ? uri.indexOf(FRAGMENT_SEPARATOR) :
2785
        fragmentLocationStyle == FRAGMENT_LAST_SEPARATOR ? uri.lastIndexOf(FRAGMENT_SEPARATOR) : -1;
2798
        fragmentLocationStyle == FRAGMENT_LAST_SEPARATOR ? uri.lastIndexOf(FRAGMENT_SEPARATOR) : -1;
Lines 2798-2804 Link Here
2798
      String sspart = uri.substring(++i);
2811
      String sspart = uri.substring(++i);
2799
      result.append(encode(sspart, URIC_HI, URIC_LO, ignoreEscaped));
2812
      result.append(encode(sspart, URIC_HI, URIC_LO, ignoreEscaped));
2800
    }
2813
    }
2801
    
2814
2802
    return result.toString();
2815
    return result.toString();
2803
  }
2816
  }
2804
2817
Lines 2871-2877 Link Here
2871
2884
2872
    for (int i = 0, len = value.length(); i < len; i++)
2885
    for (int i = 0, len = value.length(); i < len; i++)
2873
    {
2886
    {
2874
      if (isEscaped(value, i)) 
2887
      if (isEscaped(value, i))
2875
      {
2888
      {
2876
        if (result == null)
2889
        if (result == null)
2877
        {
2890
        {
Lines 2918-2929 Link Here
2918
   * Returns <code>true</code> if this URI contains non-ASCII characters;
2931
   * Returns <code>true</code> if this URI contains non-ASCII characters;
2919
   * <code>false</code> otherwise.
2932
   * <code>false</code> otherwise.
2920
   *
2933
   *
2921
   * This unused code is included for possible future use... 
2934
   * This unused code is included for possible future use...
2922
   */
2935
   */
2923
/*
2936
/*
2924
  public boolean isIRI()
2937
  public boolean isIRI()
2925
  {
2938
  {
2926
    return iri; 
2939
    return iri;
2927
  }
2940
  }
2928
2941
2929
  // Returns true if the given string contains any non-ASCII characters;
2942
  // Returns true if the given string contains any non-ASCII characters;
Lines 2962-2968 Link Here
2962
      {
2975
      {
2963
        eSegments[i] = encodeAsASCII(segments[i]);
2976
        eSegments[i] = encodeAsASCII(segments[i]);
2964
      }
2977
      }
2965
      cachedASCIIURI = new URI(hierarchical, scheme, eAuthority, eDevice, absolutePath, eSegments, eQuery, eFragment); 
2978
      cachedASCIIURI = new URI(hierarchical, scheme, eAuthority, eDevice, absolutePath, eSegments, eQuery, eFragment);
2966
2979
2967
    }
2980
    }
2968
    return cachedASCIIURI;
2981
    return cachedASCIIURI;
(-)src/org/eclipse/emf/common/util/DelegatingEList.java (+3 lines)
Lines 32-37 Link Here
32
 */
32
 */
33
public abstract class DelegatingEList extends AbstractList implements EList, Cloneable, Serializable 
33
public abstract class DelegatingEList extends AbstractList implements EList, Cloneable, Serializable 
34
{
34
{
35
//FIXME GWT CHANGE modCount not available, file bug against GWT?
36
	protected transient int modCount = 0;
37
35
  /**
38
  /**
36
   * Creates an empty instance.
39
   * Creates an empty instance.
37
   */
40
   */
(-)src/org/eclipse/emf/common/util/BasicEMap.java (-153 / +159 lines)
Lines 17-25 Link Here
17
package  org.eclipse.emf.common.util;
17
package  org.eclipse.emf.common.util;
18
18
19
19
20
import java.io.IOException;
20
//import java.io.IOException;
21
import java.io.ObjectInputStream;
21
//import java.io.ObjectInputStream;
22
import java.io.ObjectOutputStream;
22
//import java.io.ObjectOutputStream;
23
import java.io.Serializable;
23
import java.io.Serializable;
24
import java.util.AbstractCollection;
24
import java.util.AbstractCollection;
25
import java.util.AbstractSet;
25
import java.util.AbstractSet;
Lines 36-47 Link Here
36
/**
36
/**
37
 * A highly extensible map implementation.
37
 * A highly extensible map implementation.
38
 */
38
 */
39
public class BasicEMap implements EMap, Cloneable, Serializable 
39
public class BasicEMap implements EMap, Cloneable, Serializable
40
{
40
{
41
  /**
41
  /**
42
   * An extended implementation interface for caching hash values 
42
   * An extended implementation interface for caching hash values
43
   * and for upating an entry that may be manufactured as a uninitialized instance by a factory.
43
   * and for upating an entry that may be manufactured as a uninitialized instance by a factory.
44
   * No client is expected to use this interface, 
44
   * No client is expected to use this interface,
45
   * other than to implement it in conjunction with a map implementation.
45
   * other than to implement it in conjunction with a map implementation.
46
   */
46
   */
47
  public interface Entry extends Map.Entry
47
  public interface Entry extends Map.Entry
Lines 130-145 Link Here
130
  /**
130
  /**
131
   * Creates an empty instance.
131
   * Creates an empty instance.
132
   */
132
   */
133
  public BasicEMap() 
133
  public BasicEMap()
134
  {
134
  {
135
    initializeDelegateEList();
135
    initializeDelegateEList();
136
  } 
136
  }
137
137
138
  /**
138
  /**
139
   * Initializes the {@link #delegateEList}.
139
   * Initializes the {@link #delegateEList}.
140
   * This implementation illustrates the precise pattern that is used to 
140
   * This implementation illustrates the precise pattern that is used to
141
   * delegate a list implementation's callback methods to the map implementation.
141
   * delegate a list implementation's callback methods to the map implementation.
142
   */ 
142
   */
143
  protected void initializeDelegateEList()
143
  protected void initializeDelegateEList()
144
  {
144
  {
145
    delegateEList =
145
    delegateEList =
Lines 194-200 Link Here
194
   * Creates an instance that is a copy of the map.
194
   * Creates an instance that is a copy of the map.
195
   * @param map the initial contents of the map.
195
   * @param map the initial contents of the map.
196
   */
196
   */
197
  public BasicEMap(Map map) 
197
  public BasicEMap(Map map)
198
  {
198
  {
199
    this();
199
    this();
200
    int mapSize = map.size();
200
    int mapSize = map.size();
Lines 218-224 Link Here
218
  }
218
  }
219
219
220
  /**
220
  /**
221
   * Ensures that the entry data is created 
221
   * Ensures that the entry data is created
222
   * and is populated with contents of the delegate list.
222
   * and is populated with contents of the delegate list.
223
   */
223
   */
224
  protected void ensureEntryDataExists()
224
  protected void ensureEntryDataExists()
Lines 427-433 Link Here
427
  /*
427
  /*
428
   * Javadoc copied from interface.
428
   * Javadoc copied from interface.
429
   */
429
   */
430
  public int indexOfKey(Object key) 
430
  public int indexOfKey(Object key)
431
  {
431
  {
432
    if (useEqualsForKey() && key != null)
432
    if (useEqualsForKey() && key != null)
433
    {
433
    {
Lines 458-464 Link Here
458
  /*
458
  /*
459
   * Javadoc copied from interface.
459
   * Javadoc copied from interface.
460
   */
460
   */
461
  public boolean containsKey(Object key) 
461
  public boolean containsKey(Object key)
462
  {
462
  {
463
    if (size > 0)
463
    if (size > 0)
464
    {
464
    {
Lines 477-489 Link Here
477
  /*
477
  /*
478
   * Javadoc copied from interface.
478
   * Javadoc copied from interface.
479
   */
479
   */
480
  public boolean containsValue(Object value) 
480
  public boolean containsValue(Object value)
481
  {
481
  {
482
    if (size > 0)
482
    if (size > 0)
483
    {
483
    {
484
      ensureEntryDataExists();
484
      ensureEntryDataExists();
485
485
486
      if (useEqualsForValue() && value != null) 
486
      if (useEqualsForValue() && value != null)
487
      {
487
      {
488
        for (int i = 0; i < entryData.length; ++i)
488
        for (int i = 0; i < entryData.length; ++i)
489
        {
489
        {
Lines 503-509 Link Here
503
          }
503
          }
504
        }
504
        }
505
      }
505
      }
506
      else 
506
      else
507
      {
507
      {
508
        for (int i = 0; i < entryData.length; ++i)
508
        for (int i = 0; i < entryData.length; ++i)
509
        {
509
        {
Lines 531-537 Link Here
531
  /*
531
  /*
532
   * Javadoc copied from interface.
532
   * Javadoc copied from interface.
533
   */
533
   */
534
  public Object get(Object key) 
534
  public Object get(Object key)
535
  {
535
  {
536
    if (size > 0)
536
    if (size > 0)
537
    {
537
    {
Lines 551-557 Link Here
551
  /*
551
  /*
552
   * Javadoc copied from interface.
552
   * Javadoc copied from interface.
553
   */
553
   */
554
  public Object put(Object key, Object value) 
554
  public Object put(Object key, Object value)
555
  {
555
  {
556
    ensureEntryDataExists();
556
    ensureEntryDataExists();
557
557
Lines 603-609 Link Here
603
  /*
603
  /*
604
   * Javadoc copied from source.
604
   * Javadoc copied from source.
605
   */
605
   */
606
  public Object removeKey(Object key) 
606
  public Object removeKey(Object key)
607
  {
607
  {
608
    ensureEntryDataExists();
608
    ensureEntryDataExists();
609
609
Lines 657-680 Link Here
657
    return entry.getValue();
657
    return entry.getValue();
658
  }
658
  }
659
659
660
  /* 
660
  /*
661
   * Javadoc copied from interface.
661
   * Javadoc copied from interface.
662
   */
662
   */
663
  public void putAll(Map map) 
663
  public void putAll(Map map)
664
  {
664
  {
665
    for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) 
665
    for (Iterator i = map.entrySet().iterator(); i.hasNext(); )
666
    {
666
    {
667
      Map.Entry entry = (Map.Entry)i.next();
667
      Map.Entry entry = (Map.Entry)i.next();
668
      put(entry.getKey(), entry.getValue());
668
      put(entry.getKey(), entry.getValue());
669
    }
669
    }
670
  }
670
  }
671
671
672
  /* 
672
  /*
673
   * Javadoc copied from interface.
673
   * Javadoc copied from interface.
674
   */
674
   */
675
  public void putAll(EMap map) 
675
  public void putAll(EMap map)
676
  {
676
  {
677
    for (Iterator i = map.iterator(); i.hasNext(); ) 
677
    for (Iterator i = map.iterator(); i.hasNext(); )
678
    {
678
    {
679
      Map.Entry entry = (Map.Entry)i.next();
679
      Map.Entry entry = (Map.Entry)i.next();
680
      put(entry.getKey(), entry.getValue());
680
      put(entry.getKey(), entry.getValue());
Lines 684-690 Link Here
684
  /**
684
  /**
685
   * Clears the map.
685
   * Clears the map.
686
   */
686
   */
687
  protected void doClear() 
687
  protected void doClear()
688
  {
688
  {
689
    if (entryData == null)
689
    if (entryData == null)
690
    {
690
    {
Lines 705-711 Link Here
705
  /**
705
  /**
706
   * Increments the modification count.
706
   * Increments the modification count.
707
   */
707
   */
708
  protected void doMove(Entry entry) 
708
  protected void doMove(Entry entry)
709
  {
709
  {
710
    ++modCount;
710
    ++modCount;
711
  }
711
  }
Lines 714-724 Link Here
714
   * Returns a shallow copy of this map.
714
   * Returns a shallow copy of this map.
715
   * @return a shallow copy of this map.
715
   * @return a shallow copy of this map.
716
   */
716
   */
717
  public Object clone() 
717
  public Object clone()
718
  {
718
  {
719
    try 
719
//FIXME GWT CHANGE .clone is not supported by GWT
720
    { 
720
// but creating a new list is not 100% the same!
721
      BasicEMap result = (BasicEMap)super.clone();
721
// Should we raise a bug against GWT and ask for clone-support for lists?
722
//    try
723
//    {
724
//      BasicEMap result = (BasicEMap)super.clone();
725
      BasicEMap result = new BasicEMap();
722
      if (entryData != null)
726
      if (entryData != null)
723
      {
727
      {
724
        result.entryData = newEntryData(entryData.length);
728
        result.entryData = newEntryData(entryData.length);
Lines 730-740 Link Here
730
      result.view = null;
734
      result.view = null;
731
      result.modCount = 0;
735
      result.modCount = 0;
732
      return result;
736
      return result;
733
    }
737
//    }
734
    catch (CloneNotSupportedException exception) 
738
//    catch (CloneNotSupportedException exception)
735
    {
739
//    {
736
      throw new InternalError();
740
//      throw new InternalError();
737
    }
741
//    }
738
  }
742
  }
739
743
740
  protected class DelegatingMap implements EMap.InternalMapView
744
  protected class DelegatingMap implements EMap.InternalMapView
Lines 839-878 Link Here
839
  /*
843
  /*
840
   * Javadoc copied from interface.
844
   * Javadoc copied from interface.
841
   */
845
   */
842
  public Set keySet() 
846
  public Set keySet()
843
  {
847
  {
844
    if (view == null)
848
    if (view == null)
845
    {
849
    {
846
      view = new View();
850
      view = new View();
847
    }
851
    }
848
    if (view.keySet == null) 
852
    if (view.keySet == null)
849
    {
853
    {
850
      view.keySet = 
854
      view.keySet =
851
        new AbstractSet() 
855
        new AbstractSet()
852
        {
856
        {
853
          public Iterator iterator() 
857
          public Iterator iterator()
854
          {
858
          {
855
            return BasicEMap.this.size == 0 ? ECollections.EMPTY_ELIST.iterator() : new BasicEMap.BasicEMapKeyIterator();
859
            return BasicEMap.this.size == 0 ? ECollections.EMPTY_ELIST.iterator() : new BasicEMap.BasicEMapKeyIterator();
856
          }
860
          }
857
861
858
          public int size() 
862
          public int size()
859
          {
863
          {
860
            return BasicEMap.this.size;
864
            return BasicEMap.this.size;
861
          }
865
          }
862
866
863
          public boolean contains(Object key) 
867
          public boolean contains(Object key)
864
          {
868
          {
865
            return BasicEMap.this.containsKey(key);
869
            return BasicEMap.this.containsKey(key);
866
          }
870
          }
867
871
868
          public boolean remove(Object key) 
872
          public boolean remove(Object key)
869
          {
873
          {
870
            int oldSize = BasicEMap.this.size;
874
            int oldSize = BasicEMap.this.size;
871
            BasicEMap.this.removeKey(key);
875
            BasicEMap.this.removeKey(key);
872
            return BasicEMap.this.size != oldSize;
876
            return BasicEMap.this.size != oldSize;
873
          }
877
          }
874
878
875
          public void clear() 
879
          public void clear()
876
          {
880
          {
877
            BasicEMap.this.clear();
881
            BasicEMap.this.clear();
878
          }
882
          }
Lines 884-913 Link Here
884
  /*
888
  /*
885
   * Javadoc copied from interface.
889
   * Javadoc copied from interface.
886
   */
890
   */
887
  public Collection values() 
891
  public Collection values()
888
  {
892
  {
889
    if (view == null)
893
    if (view == null)
890
    {
894
    {
891
      view = new View();
895
      view = new View();
892
    }
896
    }
893
    if (view.values == null) 
897
    if (view.values == null)
894
    {
898
    {
895
      view.values = 
899
      view.values =
896
        new AbstractCollection() 
900
        new AbstractCollection()
897
        {
901
        {
898
          public Iterator iterator() 
902
          public Iterator iterator()
899
          {
903
          {
900
            return BasicEMap.this.size == 0 ? ECollections.EMPTY_ELIST.iterator() : new BasicEMap.BasicEMapValueIterator();
904
            return BasicEMap.this.size == 0 ? ECollections.EMPTY_ELIST.iterator() : new BasicEMap.BasicEMapValueIterator();
901
          }
905
          }
902
          public int size() 
906
          public int size()
903
          {
907
          {
904
            return size;
908
            return size;
905
          }
909
          }
906
          public boolean contains(Object value) 
910
          public boolean contains(Object value)
907
          {
911
          {
908
            return containsValue(value);
912
            return containsValue(value);
909
          }
913
          }
910
          public void clear() 
914
          public void clear()
911
          {
915
          {
912
            BasicEMap.this.clear();
916
            BasicEMap.this.clear();
913
          }
917
          }
Lines 919-947 Link Here
919
  /*
923
  /*
920
   * Javadoc copied from interface.
924
   * Javadoc copied from interface.
921
   */
925
   */
922
  public Set entrySet() 
926
  public Set entrySet()
923
  {
927
  {
924
    if (view == null)
928
    if (view == null)
925
    {
929
    {
926
      view = new View();
930
      view = new View();
927
    }
931
    }
928
    if (view.entrySet == null) 
932
    if (view.entrySet == null)
929
    {
933
    {
930
      view.entrySet = new AbstractSet() 
934
      view.entrySet = new AbstractSet()
931
      {
935
      {
932
        public int size() 
936
        public int size()
933
        {
937
        {
934
          return BasicEMap.this.size;
938
          return BasicEMap.this.size;
935
        }
939
        }
936
940
937
        public boolean contains(Object object) 
941
        public boolean contains(Object object)
938
        {
942
        {
939
          if (BasicEMap.this.size > 0 && object instanceof Map.Entry)
943
          if (BasicEMap.this.size > 0 && object instanceof Map.Entry)
940
          {
944
          {
941
            BasicEMap.this.ensureEntryDataExists();
945
            BasicEMap.this.ensureEntryDataExists();
942
            Map.Entry otherEntry = (Map.Entry)object;
946
            Map.Entry otherEntry = (Map.Entry)object;
943
            Object key = otherEntry.getKey();
947
            Object key = otherEntry.getKey();
944
  
948
945
            int hash = key == null ? 0 : key.hashCode();
949
            int hash = key == null ? 0 : key.hashCode();
946
            int index = BasicEMap.this.indexOf(hash);
950
            int index = BasicEMap.this.indexOf(hash);
947
            BasicEList eList = entryData[index];
951
            BasicEList eList = entryData[index];
Lines 962-968 Link Here
962
          return false;
966
          return false;
963
        }
967
        }
964
968
965
        public boolean remove(Object object) 
969
        public boolean remove(Object object)
966
        {
970
        {
967
          if (BasicEMap.this.size > 0 && object instanceof Map.Entry)
971
          if (BasicEMap.this.size > 0 && object instanceof Map.Entry)
968
          {
972
          {
Lines 979-985 Link Here
979
              for (int j = 0; j < size; ++j)
983
              for (int j = 0; j < size; ++j)
980
              {
984
              {
981
                Entry entry = entries[j];
985
                Entry entry = entries[j];
982
                if (entry.getHash() == hash && entry.equals(otherEntry)) 
986
                if (entry.getHash() == hash && entry.equals(otherEntry))
983
                {
987
                {
984
                  // BasicEMap.this.removeEntry(index, j);
988
                  // BasicEMap.this.removeEntry(index, j);
985
                  remove(otherEntry);
989
                  remove(otherEntry);
Lines 991-1002 Link Here
991
          return false;
995
          return false;
992
        }
996
        }
993
997
994
        public void clear() 
998
        public void clear()
995
        {
999
        {
996
          BasicEMap.this.clear();
1000
          BasicEMap.this.clear();
997
        }
1001
        }
998
1002
999
        public Iterator iterator() 
1003
        public Iterator iterator()
1000
        {
1004
        {
1001
          return BasicEMap.this.size == 0 ? ECollections.EMPTY_ELIST.iterator() : new BasicEMap.BasicEMapIterator();
1005
          return BasicEMap.this.size == 0 ? ECollections.EMPTY_ELIST.iterator() : new BasicEMap.BasicEMapIterator();
1002
        }
1006
        }
Lines 1009-1015 Link Here
1009
  /**
1013
  /**
1010
   * A simple and obvious entry implementation.
1014
   * A simple and obvious entry implementation.
1011
   */
1015
   */
1012
  protected class EntryImpl implements Entry 
1016
  protected class EntryImpl implements Entry
1013
  {
1017
  {
1014
    /**
1018
    /**
1015
     * The cached hash code of the key.
1019
     * The cached hash code of the key.
Lines 1025-1031 Link Here
1025
     * The value.
1029
     * The value.
1026
     */
1030
     */
1027
    protected Object value;
1031
    protected Object value;
1028
  
1032
1029
    /**
1033
    /**
1030
     * Creates a fully initialized instance.
1034
     * Creates a fully initialized instance.
1031
     * @param hash the hash code of the key.
1035
     * @param hash the hash code of the key.
Lines 1043-1074 Link Here
1043
     * Returns a new entry just like this one.
1047
     * Returns a new entry just like this one.
1044
     * @return a new entry just like this one.
1048
     * @return a new entry just like this one.
1045
     */
1049
     */
1046
    protected Object clone() 
1050
    protected Object clone()
1047
    {
1051
    {
1048
      return newEntry(hash, key, value);
1052
      return newEntry(hash, key, value);
1049
    }
1053
    }
1050
1054
1051
    public int getHash() 
1055
    public int getHash()
1052
    {
1056
    {
1053
      return hash;
1057
      return hash;
1054
    }
1058
    }
1055
1059
1056
    public void setHash(int hash) 
1060
    public void setHash(int hash)
1057
    {
1061
    {
1058
      this.hash = hash;
1062
      this.hash = hash;
1059
    }
1063
    }
1060
1064
1061
    public Object getKey() 
1065
    public Object getKey()
1062
    {
1066
    {
1063
      return key;
1067
      return key;
1064
    }
1068
    }
1065
1069
1066
    public void setKey(Object key) 
1070
    public void setKey(Object key)
1067
    {
1071
    {
1068
      throw new RuntimeException();
1072
      throw new RuntimeException();
1069
    }
1073
    }
1070
1074
1071
    public Object getValue() 
1075
    public Object getValue()
1072
    {
1076
    {
1073
      return value;
1077
      return value;
1074
    }
1078
    }
Lines 1082-1094 Link Here
1082
      return oldValue;
1086
      return oldValue;
1083
    }
1087
    }
1084
1088
1085
    public boolean equals(Object object) 
1089
    public boolean equals(Object object)
1086
    {
1090
    {
1087
      if (object instanceof Map.Entry)
1091
      if (object instanceof Map.Entry)
1088
      {
1092
      {
1089
        Map.Entry entry = (Map.Entry)object;
1093
        Map.Entry entry = (Map.Entry)object;
1090
  
1094
1091
        return 
1095
        return
1092
          (BasicEMap.this.useEqualsForKey() && key != null ? key.equals(entry.getKey()) : key == entry.getKey())  &&
1096
          (BasicEMap.this.useEqualsForKey() && key != null ? key.equals(entry.getKey()) : key == entry.getKey())  &&
1093
          (BasicEMap.this.useEqualsForValue() && value != null ? value.equals(entry.getValue()) : value == entry.getValue());
1097
          (BasicEMap.this.useEqualsForValue() && value != null ? value.equals(entry.getValue()) : value == entry.getValue());
1094
      }
1098
      }
Lines 1098-1109 Link Here
1098
      }
1102
      }
1099
    }
1103
    }
1100
1104
1101
    public int hashCode() 
1105
    public int hashCode()
1102
    {
1106
    {
1103
      return hash ^ (value == null ? 0 : value.hashCode());
1107
      return hash ^ (value == null ? 0 : value.hashCode());
1104
    }
1108
    }
1105
1109
1106
    public String toString() 
1110
    public String toString()
1107
    {
1111
    {
1108
      return key + "->" + value;
1112
      return key + "->" + value;
1109
    }
1113
    }
Lines 1112-1118 Link Here
1112
  /**
1116
  /**
1113
   * An iterator over the map entry data.
1117
   * An iterator over the map entry data.
1114
   */
1118
   */
1115
  protected class BasicEMapIterator implements Iterator 
1119
  protected class BasicEMapIterator implements Iterator
1116
  {
1120
  {
1117
    /**
1121
    /**
1118
     * The cursor in the entry data.
1122
     * The cursor in the entry data.
Lines 1195-1201 Link Here
1195
     * Returns whether there are more objects.
1199
     * Returns whether there are more objects.
1196
     * @return whether there are more objects.
1200
     * @return whether there are more objects.
1197
     */
1201
     */
1198
    public boolean hasNext() 
1202
    public boolean hasNext()
1199
    {
1203
    {
1200
      return entryCursor != -1;
1204
      return entryCursor != -1;
1201
    }
1205
    }
Lines 1205-1211 Link Here
1205
     * @return the next object.
1209
     * @return the next object.
1206
     * @exception NoSuchElementException if the iterator is done.
1210
     * @exception NoSuchElementException if the iterator is done.
1207
     */
1211
     */
1208
    public Object next() 
1212
    public Object next()
1209
    {
1213
    {
1210
      if (BasicEMap.this.modCount != expectedModCount)
1214
      if (BasicEMap.this.modCount != expectedModCount)
1211
      {
1215
      {
Lines 1231-1237 Link Here
1231
     * if <code>next</code> has not yet been called,
1235
     * if <code>next</code> has not yet been called,
1232
     * or <code>remove</code> has already been called after the last call to <code>next</code>.
1236
     * or <code>remove</code> has already been called after the last call to <code>next</code>.
1233
     */
1237
     */
1234
    public void remove() 
1238
    public void remove()
1235
    {
1239
    {
1236
      if (modCount != expectedModCount)
1240
      if (modCount != expectedModCount)
1237
      {
1241
      {
Lines 1330-1354 Link Here
1330
    BasicEList eList = entryData[index];
1334
    BasicEList eList = entryData[index];
1331
    if (eList != null)
1335
    if (eList != null)
1332
    {
1336
    {
1333
      Entry [] entries = (Entry [])eList.data;
1337
      //FIXME GWT CHANGE => Needed because BasicEList#toArray(Object[] array not working)
1338
      Object [] entries = eList.data;
1334
      int size = eList.size;
1339
      int size = eList.size;
1335
      if (useEqualsForKey() && key != null) 
1340
      if (useEqualsForKey() && key != null)
1336
      {
1341
      {
1337
        for (int j = 0; j < size; ++j)
1342
        for (int j = 0; j < size; ++j)
1338
        {
1343
        {
1339
          Entry entry = entries[j];
1344
          Entry entry = (Entry) entries[j];
1340
          if (entry.getHash() == hash && key.equals(entry.getKey())) 
1345
          if (entry.getHash() == hash && key.equals(entry.getKey()))
1341
          {
1346
          {
1342
            return entry;
1347
            return entry;
1343
          }
1348
          }
1344
        }
1349
        }
1345
      } 
1350
      }
1346
      else 
1351
      else
1347
      {
1352
      {
1348
        for (int j = 0; j < size; ++j)
1353
        for (int j = 0; j < size; ++j)
1349
        {
1354
        {
1350
          Entry entry = entries[j];
1355
          Entry entry = (Entry) entries[j];
1351
          if (entry.getKey() == key) 
1356
          if (entry.getKey() == key)
1352
          {
1357
          {
1353
            return entry;
1358
            return entry;
1354
          }
1359
          }
Lines 1368-1374 Link Here
1368
   */
1373
   */
1369
  protected int entryIndexForKey(int index, int hash, Object key)
1374
  protected int entryIndexForKey(int index, int hash, Object key)
1370
  {
1375
  {
1371
    if (useEqualsForKey() && key != null) 
1376
    if (useEqualsForKey() && key != null)
1372
    {
1377
    {
1373
      BasicEList eList = entryData[index];
1378
      BasicEList eList = entryData[index];
1374
      if (eList != null)
1379
      if (eList != null)
Lines 1378-1391 Link Here
1378
        for (int j = 0; j < size; ++j)
1383
        for (int j = 0; j < size; ++j)
1379
        {
1384
        {
1380
          Entry entry = entries[j];
1385
          Entry entry = entries[j];
1381
          if (entry.getHash() == hash && key.equals(entry.getKey())) 
1386
          if (entry.getHash() == hash && key.equals(entry.getKey()))
1382
          {
1387
          {
1383
            return j;
1388
            return j;
1384
          }
1389
          }
1385
        }
1390
        }
1386
      }
1391
      }
1387
    } 
1392
    }
1388
    else 
1393
    else
1389
    {
1394
    {
1390
      BasicEList eList = entryData[index];
1395
      BasicEList eList = entryData[index];
1391
      if (eList != null)
1396
      if (eList != null)
Lines 1395-1401 Link Here
1395
        for (int j = 0; j < size; ++j)
1400
        for (int j = 0; j < size; ++j)
1396
        {
1401
        {
1397
          Entry entry = entries[j];
1402
          Entry entry = entries[j];
1398
          if (entry.getKey() == key) 
1403
          if (entry.getKey() == key)
1399
          {
1404
          {
1400
            return j;
1405
            return j;
1401
          }
1406
          }
Lines 1410-1416 Link Here
1410
   * Grows the capacity of the map
1415
   * Grows the capacity of the map
1411
   * to ensure that no additional growth is needed until the size exceeds the specified minimun capacity.
1416
   * to ensure that no additional growth is needed until the size exceeds the specified minimun capacity.
1412
   */
1417
   */
1413
  protected boolean grow(int minimumCapacity) 
1418
  protected boolean grow(int minimumCapacity)
1414
  {
1419
  {
1415
    ++modCount;
1420
    ++modCount;
1416
    int oldCapacity = entryData == null ? 0 : entryData.length;
1421
    int oldCapacity = entryData == null ? 0 : entryData.length;
Lines 1424-1434 Link Here
1424
        BasicEList oldEList = oldEntryData[i];
1429
        BasicEList oldEList = oldEntryData[i];
1425
        if (oldEList != null)
1430
        if (oldEList != null)
1426
        {
1431
        {
1427
          Entry [] entries = (Entry [])oldEList.data;
1432
          //FIXME GWT CHANGE => Needed because BasicEList#toArray(Object[] array not working)
1433
          Object [] entries = oldEList.data;
1428
          int size = oldEList.size;
1434
          int size = oldEList.size;
1429
          for (int j = 0; j < size; ++j)
1435
          for (int j = 0; j < size; ++j)
1430
          {
1436
          {
1431
            Entry entry = entries[j];
1437
            Entry entry = (Entry) entries[j];
1432
            int index = indexOf(entry.getHash());
1438
            int index = indexOf(entry.getHash());
1433
            BasicEList eList = entryData[index];
1439
            BasicEList eList = entryData[index];
1434
            if (eList == null)
1440
            if (eList == null)
Lines 1447-1508 Link Here
1447
      return false;
1453
      return false;
1448
    }
1454
    }
1449
  }
1455
  }
1450
1456
//XXX GWT CHANGE Serialization not available
1451
  private void writeObject(ObjectOutputStream objectOutputStream) throws IOException
1457
//  private void writeObject(ObjectOutputStream objectOutputStream) throws IOException
1452
  {
1458
//  {
1453
    objectOutputStream.defaultWriteObject();
1459
//    objectOutputStream.defaultWriteObject();
1454
1460
//
1455
    if (entryData == null)
1461
//    if (entryData == null)
1456
    {
1462
//    {
1457
      objectOutputStream.writeInt(0);
1463
//      objectOutputStream.writeInt(0);
1458
    }
1464
//    }
1459
    else
1465
//    else
1460
    {
1466
//    {
1461
      // Write the capacity.
1467
//      // Write the capacity.
1462
      //
1468
//      //
1463
      objectOutputStream.writeInt(entryData.length);
1469
//      objectOutputStream.writeInt(entryData.length);
1464
  
1470
//
1465
      // Write all the entryData; there will be size of them.
1471
//      // Write all the entryData; there will be size of them.
1466
      //
1472
//      //
1467
      for (int i = 0; i < entryData.length; ++i)
1473
//      for (int i = 0; i < entryData.length; ++i)
1468
      {
1474
//      {
1469
        BasicEList eList = entryData[i];
1475
//        BasicEList eList = entryData[i];
1470
        if (eList != null)
1476
//        if (eList != null)
1471
        {
1477
//        {
1472
          Entry [] entries = (Entry [])eList.data;
1478
//          Entry [] entries = (Entry [])eList.data;
1473
          int size = eList.size;
1479
//          int size = eList.size;
1474
          for (int j = 0; j < size; ++j)
1480
//          for (int j = 0; j < size; ++j)
1475
          {
1481
//          {
1476
            Entry entry = entries[j];
1482
//            Entry entry = entries[j];
1477
            objectOutputStream.writeObject(entry.getKey());
1483
//            objectOutputStream.writeObject(entry.getKey());
1478
            objectOutputStream.writeObject(entry.getValue());
1484
//            objectOutputStream.writeObject(entry.getValue());
1479
          }
1485
//          }
1480
        }
1486
//        }
1481
      }
1487
//      }
1482
    }
1488
//    }
1483
  }
1489
//  }
1484
1490
//
1485
  private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException
1491
//  private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException
1486
  {
1492
//  {
1487
    objectInputStream.defaultReadObject();
1493
//    objectInputStream.defaultReadObject();
1488
  
1494
//
1489
    // Restore the capacity, if there was any.
1495
//    // Restore the capacity, if there was any.
1490
    //
1496
//    //
1491
    int capacity = objectInputStream.readInt();
1497
//    int capacity = objectInputStream.readInt();
1492
    if (capacity > 0)
1498
//    if (capacity > 0)
1493
    {
1499
//    {
1494
      entryData = newEntryData(capacity);
1500
//      entryData = newEntryData(capacity);
1495
    
1501
//
1496
      // Read all size number of entryData.
1502
//      // Read all size number of entryData.
1497
      //
1503
//      //
1498
      for (int i = 0; i < size; ++i) 
1504
//      for (int i = 0; i < size; ++i)
1499
      {
1505
//      {
1500
        Object key = objectInputStream.readObject();
1506
//        Object key = objectInputStream.readObject();
1501
        Object value = objectInputStream.readObject();
1507
//        Object value = objectInputStream.readObject();
1502
        put(key, value);
1508
//        put(key, value);
1503
      }
1509
//      }
1504
    }
1510
//    }
1505
  }
1511
//  }
1506
1512
1507
  /**
1513
  /**
1508
   * Delegates to {@link #delegateEList}.
1514
   * Delegates to {@link #delegateEList}.
(-)src/org/eclipse/emf/common/CommonPlugin.java (-196 / +18 lines)
Lines 1-201 Link Here
1
/**
2
 * <copyright> 
3
 *
4
 * Copyright (c) 2002-2004 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors: 
11
 *   IBM - Initial API and implementation
12
 *
13
 * </copyright>
14
 *
15
 * $Id: CommonPlugin.java,v 1.11 2006/02/14 18:14:43 marcelop Exp $
16
 */
17
package org.eclipse.emf.common;
1
package org.eclipse.emf.common;
18
2
3
public class CommonPlugin {
19
4
20
import java.io.IOException;
5
	public static final CommonPlugin INSTANCE = new CommonPlugin();
21
import java.net.URL;
6
7
	public static Class loadClass(String string, String string2) {
8
		throw new UnsupportedOperationException();
9
	}
10
11
	public String getString(String string, String[] strings) {
12
		return string;
13
	}
14
15
	public String getString(String string) {
16
		return string;
17
	}
18
19
	public void log(Throwable fillInStackTrace) {
20
		System.err.println(fillInStackTrace.toString());
21
	}
22
22
23
import org.eclipse.core.runtime.Platform;
24
import org.eclipse.emf.common.util.ResourceLocator;
25
import org.eclipse.emf.common.util.URI;
26
27
28
/**
29
 * The <b>Plugin</b> for the model EMF.Common library.
30
 * EMF must run 
31
 * within an Eclipse workbench,
32
 * within a headless Eclipse workspace,
33
 * or just stand-alone as part of some other application.
34
 * To support this, all resource access should be directed to the resource locator,
35
 * which can redirect the service as appopriate to the runtime.
36
 * During stand-alone invocation no plugin initialization takes place.
37
 * In this case, common.resources.jar must be on the CLASSPATH.
38
 * @see #INSTANCE
39
 */
40
public final class CommonPlugin extends EMFPlugin 
41
{
42
  /**
43
   * The singleton instance of the plugin.
44
   */
45
  public static final CommonPlugin INSTANCE = new CommonPlugin();
46
47
  /**
48
   * The one instance of this class.
49
   */
50
  private static Implementation plugin;
51
52
  /**
53
   * Creates the singleton instance.
54
   */
55
  private CommonPlugin()
56
  {
57
    super(new ResourceLocator[] {});
58
  }
59
60
  /*
61
   * Javadoc copied from base class.
62
   */
63
  public ResourceLocator getPluginResourceLocator()
64
  {
65
    return plugin;
66
  }
67
68
  /**
69
   * Returns the singleton instance of the Eclipse plugin.
70
   * @return the singleton instance.
71
   */
72
  public static Implementation getPlugin()
73
  {
74
    return plugin;
75
  }
76
77
  /**
78
   * Use the platform, if available, to convert to a local URI.
79
   */
80
  public static URI asLocalURI(URI uri)
81
  {
82
    return plugin == null ? uri : Implementation.asLocalURI(uri);
83
  }
84
85
  /**
86
   * Use the platform, if available, to resolve the URI.
87
   */
88
  public static URI resolve(URI uri)
89
  {
90
    return plugin == null ? uri : Implementation.resolve(uri);
91
  }
92
93
  /**
94
   * Use the platform, if available, to load the named class using the right class loader.
95
   */
96
  public static Class loadClass(String pluginID, String className) throws ClassNotFoundException
97
  {
98
    return plugin == null ? Class.forName(className) : Implementation.loadClass(pluginID, className);
99
  }
100
101
  /**
102
   * The actual implementation of the Eclipse <b>Plugin</b>.
103
   */
104
  public static class Implementation extends EclipsePlugin 
105
  {
106
    /**
107
     * Creates an instance.
108
     */
109
    public Implementation()
110
    {
111
      super();
112
113
      // Remember the static instance.
114
      //
115
      plugin = this;
116
    }
117
118
    /**
119
     * Use the platform to convert to a local URI.
120
     */
121
    protected static URI asLocalURI(URI uri)
122
    {
123
      try
124
      {
125
        String fragment = uri.fragment();
126
        URL url = Platform.asLocalURL(new URL(uri.trimFragment().toString()));
127
        return fix(url, fragment);
128
      }
129
      catch (IOException exception)
130
      {
131
      }
132
      return uri;
133
    }
134
135
    /**
136
     * Use the platform to convert to a local URI.
137
     */
138
    protected static URI resolve(URI uri)
139
    {
140
      String fragment = uri.fragment();
141
      URI uriWithoutFragment = uri.trimFragment();
142
      String uriWithoutFragmentToString = uriWithoutFragment.toString();
143
      
144
      URL url = null;
145
      try
146
      {
147
        url = Platform.resolve(new URL(uriWithoutFragmentToString));
148
      }
149
      catch (IOException exception1)
150
      {
151
        // Platform.resolve() doesn't work if the project is encoded.
152
        //
153
        try
154
        {
155
          uriWithoutFragmentToString = URI.decode(uriWithoutFragmentToString);
156
          url = Platform.resolve(new URL(uriWithoutFragmentToString));
157
        }
158
        catch (IOException exception2)
159
        {
160
        }
161
      }
162
      if (url != null)
163
      {
164
        try
165
        {
166
          return fix(url, fragment);
167
        }
168
        catch (IOException exception)
169
        {
170
        }
171
      }
172
      
173
      return uri;
174
    }
175
176
    protected static URI fix(URL url, String fragment) throws IOException
177
    {
178
      // Only file-scheme URIs will be re-encoded. If a URI was decoded in the workaround
179
      // above, and Platform.resolve() didn't return a file-scheme URI, then this will return
180
      // an decoded URI.
181
      //
182
      URI result = 
183
        "file".equalsIgnoreCase(url.getProtocol()) ?
184
          URI.createFileURI(URI.decode(url.getFile())) :
185
          URI.createURI(url.toString());
186
      if (fragment != null)
187
      {
188
        result = result.appendFragment(fragment);
189
      }
190
      return result;
191
    }
192
    
193
    /**
194
     * Use the platform to load the named class using the right class loader.
195
     */
196
    public static Class loadClass(String pluginID, String className) throws ClassNotFoundException
197
    {
198
      return Platform.getBundle(pluginID).loadClass(className);
199
    }
200
  }
201
}
23
}
(-)src/org/eclipse/emf/common/EMFPlugin.java (-827 / +2 lines)
Lines 1-832 Link Here
1
/**
2
 * <copyright> 
3
 *
4
 * Copyright (c) 2002-2006 IBM Corporation and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors: 
11
 *   IBM - Initial API and implementation
12
 *
13
 * </copyright>
14
 *
15
 * $Id: EMFPlugin.java,v 1.15 2006/09/13 18:58:14 emerks Exp $
16
 */
17
package org.eclipse.emf.common;
1
package org.eclipse.emf.common;
18
2
3
public class EMFPlugin {
19
4
20
import java.io.IOException;
5
	public static boolean IS_ECLIPSE_RUNNING = false;
21
import java.io.InputStream;
22
import java.net.MalformedURLException;
23
import java.net.URL;
24
import java.text.MessageFormat;
25
import java.util.HashMap;
26
import java.util.Map;
27
import java.util.MissingResourceException;
28
import java.util.PropertyResourceBundle;
29
import java.util.ResourceBundle;
30
import java.util.jar.Manifest;
31
6
32
import org.osgi.framework.Bundle;
33
34
import org.eclipse.core.runtime.ILog;
35
import org.eclipse.core.runtime.IStatus;
36
import org.eclipse.core.runtime.Platform;
37
import org.eclipse.core.runtime.Plugin;
38
import org.eclipse.core.runtime.Status;
39
40
import org.eclipse.emf.common.util.Logger;
41
import org.eclipse.emf.common.util.ResourceLocator;
42
import org.eclipse.emf.common.util.URI;
43
import org.eclipse.emf.common.util.WrappedException;
44
45
46
/**
47
 * EMF must run 
48
 * within an Eclipse workbench,
49
 * within a headless Eclipse workspace,
50
 * or just stand-alone as part of some other application.
51
 * To support this, all resource access (e.g., NL strings, images, and so on) is directed to the resource locator methods,
52
 * which can redirect the service as appopriate to the runtime.
53
 * During Eclipse invocation, the implementation delegates to a plugin implementation.
54
 * During stand-alone invocation, no plugin initialization takes place,
55
 * so the implementation delegates to a resource JAR on the CLASSPATH.
56
 * The resource jar will typically <b>not</b> be on the CLASSPATH during Eclipse invocation.
57
 * It will contain things like the icons and the .properties,  
58
 * which are available in a different way during Eclipse invocation.
59
 * @see ResourceLocator
60
 * @see Logger
61
 */
62
public abstract class EMFPlugin implements ResourceLocator, Logger
63
{
64
  public static final boolean IS_ECLIPSE_RUNNING;
65
  static
66
  {
67
    boolean result = false;
68
    try
69
    {
70
      result = Platform.isRunning();
71
    }
72
    catch (Throwable exception)
73
    {
74
    }
75
    IS_ECLIPSE_RUNNING = result;
76
  }
77
78
  protected ResourceLocator [] delegateResourceLocators;
79
  protected URL baseURL;
80
  protected ResourceBundle untranslatedResourceBundle;
81
  protected ResourceBundle resourceBundle;
82
  protected Map strings = new HashMap();
83
  protected Map untranslatedStrings = new HashMap();
84
  protected boolean shouldTranslate = true;
85
  protected Map images = new HashMap();
86
87
  public EMFPlugin(ResourceLocator [] delegateResourceLocators)
88
  {
89
    this.delegateResourceLocators = delegateResourceLocators;
90
  }
91
92
  /**
93
   * Returns an Eclipse plugin implementation of a resource locator.
94
   * @return an Eclipse plugin implementation of a resource locator.
95
   */
96
  public abstract ResourceLocator getPluginResourceLocator();
97
98
  /**
99
   * Returns an Eclipse plugin implementation of a logger.
100
   * @return an Eclipse plugin implementation of a logger.
101
   */
102
  public Logger getPluginLogger()
103
  {
104
    return (Logger)getPluginResourceLocator();
105
  }
106
107
  public String getSymbolicName()
108
  {
109
    ResourceLocator resourceLocator = getPluginResourceLocator();
110
    if (resourceLocator instanceof InternalEclipsePlugin)
111
    {
112
      return ((InternalEclipsePlugin)resourceLocator).getSymbolicName();
113
    }
114
    else
115
    {
116
      String result = getClass().getName();
117
      return result.substring(0, result.lastIndexOf('.'));
118
    }
119
  }
120
121
  private static final URI DOT = URI.createURI(".");
122
  /*
123
   * Javadoc copied from interface.
124
   */
125
  public URL getBaseURL()
126
  {
127
    if (baseURL == null)
128
    {
129
      if (getPluginResourceLocator() == null)
130
      {
131
        try
132
        {
133
          // Determine the base URL by looking for the plugin.properties file in the standard way.
134
          //
135
          Class theClass = getClass();
136
          URL pluginPropertiesURL = theClass.getResource("plugin.properties");
137
          if (pluginPropertiesURL == null)
138
          {
139
            // If that fails, determine the URL for the class itself.
140
            // The URL will be of one of the following forms,
141
            // so there are a few good places to consider looking for the plugin.properties.
142
            //
143
            // For a plugin.xml with runtime="common.jar":
144
            // jar:file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/common.jar!/org/eclipse/common/CommonPlugin.class
145
            //
146
            // For a plugin.xml with runtime="runtime/common.jar":
147
            // jar:file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/runtime/common.jar!/org/eclipse/common/CommonPlugin.class
148
            // 
149
            // For a plugin.xml with runtime="." where the plugin is jarred:
150
            // jar:file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common.jar!/org/eclipse/common/CommonPlugin.class
151
            //
152
            // For a plugin.xml with runtime="." where the plugin is not jarred.
153
            // file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/org/eclipse/emf/common/CommonPlugin.class
154
            //
155
            // Running in PDE with bin on classpath:
156
            // file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/bin/org/eclipse/emf/common/CommonPlugin.class
157
            //
158
            String className = theClass.getName();
159
            int index = className.lastIndexOf(".");
160
            URL classURL = theClass.getResource((index == -1 ? className : className.substring(index + 1)) + ".class");
161
            URI uri = URI.createURI(classURL.toString());
162
            
163
            // Trim off the segments corresponding to the package nesting.
164
            //
165
            int count = 1;
166
            for (int i = 0; (i = className.indexOf('.', i)) != -1; ++i)
167
            {
168
              ++count;
169
            }
170
            uri = uri.trimSegments(count);
171
            
172
            // For an archive URI, check for the plugin.properties in the archive.
173
            //
174
            if (URI.isArchiveScheme(uri.scheme()))
175
            {
176
              try
177
              {
178
                // If we can open  an input stream, then the plugin.properties is there, and we have a good base URL.
179
                //
180
                InputStream inputStream =  new URL(uri.appendSegment("plugin.properties").toString()).openStream();
181
                inputStream.close();
182
                baseURL = new URL(uri.toString());
183
              }
184
              catch (IOException exception)
185
              {
186
                // If the plugin.properties isn't within the root of the archive, 
187
                // create a new URI for the folder location of the archive, 
188
                // so we can look in the folder that contains it.
189
                //
190
                uri = URI.createURI(uri.authority()).trimSegments(1);
191
              }
192
            }
193
            
194
            // If we didn't find the plugin.properties in the usual place nor in the archive...
195
            //
196
            if (baseURL == null)
197
            {
198
              // Trim off the "bin" or "runtime" segment.
199
              //
200
              String lastSegment = uri.lastSegment();
201
              if ("bin".equals(lastSegment) || "runtime".equals(lastSegment))
202
              {
203
                uri = uri.trimSegments(1);
204
              }
205
              uri = uri.appendSegment("plugin.properties");
206
              try
207
              {
208
                // If we can open  an input stream, then the plugin.properties is in the folder, and we have a good base URL.
209
                //
210
                InputStream inputStream = new URL(uri.toString()).openStream();
211
                inputStream.close();
212
                baseURL = new URL(DOT.resolve(uri).toString());
213
              }
214
              catch (IOException exception)
215
              {
216
              }
217
            }
218
            
219
            // If we still don't have a good base URL, complain about it.
220
            //
221
            if (baseURL == null)
222
            {
223
              String resourceName = 
224
                index == -1 ? 
225
                  "plugin.properties" : 
226
                  className.substring(0, index + 1).replace('.','/') + "plugin.properties";
227
              throw new MissingResourceException("Missing properties: " + resourceName, theClass.getName(), "plugin.properties");
228
            }
229
          }
230
          else
231
          {
232
            baseURL = new URL(DOT.resolve(URI.createURI(pluginPropertiesURL.toString())).toString());
233
          }
234
        }
235
        catch (IOException exception)
236
        {
237
          throw new WrappedException(exception);
238
        }
239
      }
240
      else
241
      {
242
        baseURL = getPluginResourceLocator().getBaseURL();
243
      }
244
    }
245
246
    return baseURL;
247
  } 
248
249
  /*
250
   * Javadoc copied from interface.
251
   */
252
  public Object getImage(String key)
253
  {
254
    Object result = (URL)images.get(key);
255
    if (result == null)
256
    {
257
      if (getPluginResourceLocator() == null)
258
      {
259
        try
260
        {
261
          result = doGetImage(key);
262
        }
263
        catch (MalformedURLException exception)
264
        {
265
          throw new WrappedException(exception);
266
        }
267
        catch (IOException exception)
268
        {
269
          result = delegatedGetImage(key);
270
        }
271
      }
272
      else
273
      {
274
        try
275
        {
276
          result = getPluginResourceLocator().getImage(key);
277
        }
278
        catch (MissingResourceException exception)
279
        {
280
          result = delegatedGetImage(key);
281
        }
282
      }
283
284
      images.put(key, result);
285
    }
286
287
    return result;
288
  }
289
290
  /**
291
   * Does the work of fetching the image associated with the key.
292
   * It ensures that the image exists.
293
   * @param key the key of the image to fetch.
294
   * @exception IOException if an image doesn't exist.
295
   * @return the description of the image associated with the key.
296
   */
297
  protected Object doGetImage(String key) throws IOException
298
  {
299
    URL url = new URL(getBaseURL() + "icons/" + key + ".gif");
300
    InputStream inputStream = url.openStream(); 
301
    inputStream.close();
302
    return url;
303
  }
304
305
  /**
306
   * Does the work of fetching the image associated with the key,
307
   * when the image resource is not available locally.
308
   * @param key the key of the image to fetch.
309
   * @exception MissingResourceException if the image resource doesn't exist anywhere.
310
   * @see #delegateResourceLocators
311
   */
312
  protected Object delegatedGetImage(String key) throws MissingResourceException
313
  {
314
    for (int i = 0; i < delegateResourceLocators.length; ++i)
315
    {
316
      try
317
      {
318
        return delegateResourceLocators[i].getImage(key);
319
      }
320
      catch (MissingResourceException exception)
321
      {
322
      }
323
    }
324
325
    throw 
326
      new MissingResourceException
327
        (CommonPlugin.INSTANCE.getString("_UI_ImageResourceNotFound_exception", new Object [] { key }),
328
         getClass().getName(), 
329
         key);
330
  }
331
332
  /**
333
   * Indicates whether strings should be translated by default.
334
   * 
335
   * @return <code>true</code> if strings should be translated by default; <code>false</code> otherwise.
336
   */
337
  public boolean shouldTranslate()
338
  {
339
    return shouldTranslate;
340
  }
341
342
  /**
343
   * Sets whether strings should be translated by default.
344
   * 
345
   * @param shouldTranslate whether strings should be translated by default.
346
   */
347
  public void setShouldTranslate(boolean shouldTranslate)
348
  {
349
    this.shouldTranslate = shouldTranslate;
350
  }
351
352
  /*
353
   * Javadoc copied from interface.
354
   */
355
  public String getString(String key)
356
  {
357
    return getString(key, shouldTranslate());
358
  }
359
360
  /*
361
   * Javadoc copied from interface.
362
   */
363
  public String getString(String key, boolean translate)
364
  {
365
    Map stringMap = translate ? strings : untranslatedStrings;
366
    String result = (String)stringMap.get(key);
367
    if (result == null)
368
    {
369
      try
370
      {
371
        if (getPluginResourceLocator() == null)
372
        {
373
          ResourceBundle bundle = translate ? resourceBundle : untranslatedResourceBundle;
374
          if (bundle == null)
375
          {
376
            String packageName = getClass().getName();
377
            int index = packageName.lastIndexOf(".");
378
            if (index != -1)
379
            {
380
              packageName = packageName.substring(0, index);
381
            }
382
            if (translate)
383
            {
384
              try
385
              {
386
                bundle = resourceBundle = ResourceBundle.getBundle(packageName + ".plugin");
387
              }
388
              catch (MissingResourceException exception)
389
              {
390
                // If the bundle can't be found the normal way, try to find it as the base URL.
391
                // If that also doesn't work, rethrow the original exception.
392
                //
393
                try
394
                {
395
                  InputStream inputStream =  new URL(getBaseURL().toString() + "plugin.properties").openStream();
396
                  bundle = untranslatedResourceBundle = resourceBundle = new PropertyResourceBundle(inputStream);
397
                  inputStream.close();
398
                }
399
                catch (IOException ioException)
400
                {
401
                }
402
                if (resourceBundle == null)
403
                {
404
                  throw exception; 
405
                }
406
              }
407
            }
408
            else
409
            {
410
              String resourceName = getBaseURL().toString() + "plugin.properties";
411
              try
412
              {
413
                InputStream inputStream =  new URL(resourceName).openStream();
414
                bundle = untranslatedResourceBundle = new PropertyResourceBundle(inputStream);
415
                inputStream.close();
416
              }
417
              catch (IOException ioException)
418
              {
419
                throw new MissingResourceException("Missing properties: " + resourceName, getClass().getName(), "plugin.properties");
420
              }
421
            }
422
          }
423
          result = bundle.getString(key);
424
        }
425
        else
426
        {
427
          result = getPluginResourceLocator().getString(key, translate);
428
        }
429
      }
430
      catch (MissingResourceException exception)
431
      {
432
        result = delegatedGetString(key, translate);
433
      }
434
  
435
      stringMap.put(key, result);
436
    }
437
438
    return result;
439
  }
440
441
  /**
442
   * Does the work of fetching the string associated with the key,
443
   * when the string resource is not available locally.
444
   * @param key the key of the string to fetch.
445
   * @exception MissingResourceException if the string resource doesn't exist anywhere.
446
   * @see #delegateResourceLocators
447
   */
448
  protected String delegatedGetString(String key, boolean translate)
449
  {
450
    for (int i = 0; i < delegateResourceLocators.length; ++i)
451
    {
452
      try
453
      {
454
        return delegateResourceLocators[i].getString(key, translate);
455
      }
456
      catch (MissingResourceException exception)
457
      {
458
      }
459
    }
460
461
    throw 
462
      new MissingResourceException
463
        (MessageFormat.format("The string resource ''{0}'' could not be located", new Object [] { key }),
464
         getClass().getName(), 
465
         key);
466
  }
467
468
  /*
469
   * Javadoc copied from interface.
470
   */
471
  public String getString(String key, Object [] substitutions)
472
  {
473
    return getString(key, substitutions, shouldTranslate());
474
  }
475
  
476
  /*
477
   * Javadoc copied from interface.
478
   */
479
  public String getString(String key, Object [] substitutions, boolean translate)
480
  {
481
    return MessageFormat.format(getString(key, translate), substitutions);
482
  }
483
484
  /*
485
   * Javadoc copied from interface.
486
   */
487
  public void log(Object logEntry)
488
  {
489
    Logger logger = getPluginLogger();
490
    if (logger == null)
491
    {
492
      if (logEntry instanceof Throwable)
493
      {
494
        ((Throwable)logEntry).printStackTrace(System.err);
495
      }
496
      else
497
      {
498
        System.err.println(logEntry);
499
      }
500
    }
501
    else
502
    {
503
      logger.log(logEntry);
504
    }
505
  }
506
507
  /**
508
   * The actual implementation of an Eclipse <b>Plugin</b>.
509
   */
510
  public static abstract class EclipsePlugin extends Plugin implements ResourceLocator, Logger, InternalEclipsePlugin
511
  {
512
    /**
513
     * The EMF plug-in APIs are all delegated to this helper, so that code can be shared by plug-in
514
     * implementations with a different platform base class (e.g. AbstractUIPlugin).
515
     */
516
    protected InternalHelper helper;
517
    
518
    /**
519
     * Creates an instance.
520
     */
521
    public EclipsePlugin()
522
    {
523
      super();
524
      helper = new InternalHelper(this);
525
    }
526
527
    /**
528
     * Creates an instance.
529
     * @param descriptor the description of the plugin.
530
     * @deprecated
531
     */
532
    public EclipsePlugin(org.eclipse.core.runtime.IPluginDescriptor descriptor)
533
    {
534
      super(descriptor);
535
      helper = new InternalHelper(this);
536
    }
537
538
    /**
539
     * Return the plugin ID.
540
     */
541
    public String getSymbolicName()
542
    {
543
      return helper.getSymbolicName();
544
    }
545
546
    /*
547
     * Javadoc copied from interface.
548
     */
549
    public URL getBaseURL()
550
    {
551
      return helper.getBaseURL();
552
    }
553
554
    /*
555
     * Javadoc copied from interface.
556
     */
557
    public Object getImage(String key)
558
    {
559
      try
560
      {
561
        return doGetImage(key);
562
      }
563
      catch (MalformedURLException exception)
564
      {
565
        throw new WrappedException(exception);
566
      }
567
      catch (IOException exception)
568
      {
569
        throw 
570
          new MissingResourceException
571
            (CommonPlugin.INSTANCE.getString("_UI_StringResourceNotFound_exception", new Object [] { key }),
572
             getClass().getName(), 
573
             key);
574
      }
575
    }
576
577
    /**
578
     * Does the work of fetching the image associated with the key.
579
     * It ensures that the image exists.
580
     * @param key the key of the image to fetch.
581
     * @exception IOException if an image doesn't exist.
582
     * @return the description of the image associated with the key.
583
     */
584
    protected Object doGetImage(String key) throws IOException
585
    {
586
      return helper.getImage(key);
587
    }
588
589
    public String getString(String key)
590
    {
591
      return helper.getString(key, true);
592
    }
593
    
594
    public String getString(String key, boolean translate)
595
    {
596
      return helper.getString(key, translate);
597
    }
598
599
    public String getString(String key, Object [] substitutions)
600
    {
601
      return helper.getString(key, substitutions, true);
602
    }
603
604
    public String getString(String key, Object [] substitutions, boolean translate)
605
    {
606
      return helper.getString(key, substitutions, translate);
607
    }
608
609
    public void log(Object logEntry)
610
    {
611
      helper.log(logEntry);
612
    }
613
  }
614
615
  /**
616
   * This just provides a common interface for the Eclipse plugins supported by EMF.
617
   * It is not considered API and should not be used by clients.
618
   */
619
  public static interface InternalEclipsePlugin
620
  {
621
    String getSymbolicName();
622
  }
623
  
624
  /**
625
   * This just provides a common delegate for non-UI and UI plug-in classes.
626
   * It is not considered API and should not be used by clients.
627
   */
628
  public static class InternalHelper
629
  {
630
    protected Plugin plugin;
631
    protected ResourceBundle resourceBundle;
632
    protected ResourceBundle untranslatedResourceBundle;
633
634
    public InternalHelper(Plugin plugin)
635
    {
636
      this.plugin = plugin;
637
    }
638
639
    protected Bundle getBundle()
640
    {
641
      return plugin.getBundle();
642
    }
643
644
    protected ILog getLog()
645
    {
646
      return plugin.getLog();
647
    }
648
    
649
    /**
650
     * Return the plugin ID.
651
     */
652
    public String getSymbolicName()
653
    {
654
      return getBundle().getSymbolicName();
655
    }
656
657
    public URL getBaseURL()
658
    {
659
      return getBundle().getEntry("/");
660
    }
661
662
    /**
663
     * Fetches the image associated with the given key. It ensures that the image exists.
664
     * @param key the key of the image to fetch.
665
     * @exception IOException if an image doesn't exist.
666
     * @return the description of the image associated with the key.
667
     */
668
    public Object getImage(String key) throws IOException
669
    {
670
      URL url = new URL(getBaseURL() + "icons/" + key + ".gif");
671
      InputStream inputStream = url.openStream(); 
672
      inputStream.close();
673
      return url;
674
    }
675
676
    public String getString(String key, boolean translate)
677
    {
678
      ResourceBundle bundle = translate ? resourceBundle : untranslatedResourceBundle;
679
      if (bundle == null)
680
      {
681
        if (translate)
682
        {
683
           bundle = resourceBundle = Platform.getResourceBundle(getBundle());
684
        }
685
        else
686
        {
687
          String resourceName = getBaseURL().toString() + "plugin.properties";
688
          try
689
          {
690
            InputStream inputStream =  new URL(resourceName).openStream();
691
            bundle = untranslatedResourceBundle = new PropertyResourceBundle(inputStream);
692
            inputStream.close();
693
          }
694
          catch (IOException ioException)
695
          {
696
            throw new MissingResourceException("Missing properties: " + resourceName, getClass().getName(), "plugin.properties");
697
          }
698
        }
699
      }
700
      return bundle.getString(key);
701
    }
702
703
    public String getString(String key, Object [] substitutions, boolean translate)
704
    {
705
      return MessageFormat.format(getString(key, translate), substitutions);
706
    }
707
708
    public void log(Object logEntry)
709
    {
710
      IStatus status;
711
      if (logEntry instanceof IStatus)
712
      {
713
        status = (IStatus)logEntry;
714
        getLog().log(status);
715
      }
716
      else 
717
      {
718
        if (logEntry == null)
719
        {
720
          logEntry = new RuntimeException(getString("_UI_NullLogEntry_exception", true)).fillInStackTrace();
721
        }
722
723
        if (logEntry instanceof Throwable)
724
        {
725
          Throwable throwable = (Throwable)logEntry;
726
727
          // System.err.println("Logged throwable: --------------------");
728
          // throwable.printStackTrace();
729
730
          String message = throwable.getLocalizedMessage();
731
          if (message == null)
732
          {
733
            message = "";
734
          }
735
736
          getLog().log(new Status(IStatus.WARNING, getBundle().getSymbolicName(), 0, message, throwable));
737
        }
738
        else
739
        {
740
          // System.err.println("Logged throwable: --------------------");
741
          // throwable.printStackTrace();
742
743
          getLog().log (new Status (IStatus.WARNING, getBundle().getSymbolicName(), 0, logEntry.toString(), null));
744
        }
745
      }
746
    } 
747
  }
748
749
  public static void main(String[] args)
750
  {
751
    try
752
    {
753
      String [] relativePath = { "META-INF", "MANIFEST.MF" };
754
      Class theClass =  args.length > 0 ? Class.forName(args[0]) : EMFPlugin.class;
755
756
      String className = theClass.getName();
757
      int index = className.lastIndexOf(".");
758
      URL classURL = theClass.getResource((index == -1 ? className : className.substring(index + 1)) + ".class");
759
      URI uri = URI.createURI(classURL.toString());
760
761
      // Trim off the segments corresponding to the package nesting.
762
      //
763
      int count = 1;
764
      for (int i = 0; (i = className.indexOf('.', i)) != -1; ++i)
765
      {
766
        ++count;
767
      }
768
      uri = uri.trimSegments(count);
769
770
      URL manifestURL = null;
771
  
772
      // For an archive URI, check for the path in the archive.
773
      //
774
      if (URI.isArchiveScheme(uri.scheme()))
775
      {
776
        try
777
        {
778
          // If we can open  an input stream, then the path is there, and we have a good URL.
779
          //
780
          String manifestURI = uri.appendSegments(relativePath).toString();
781
          InputStream inputStream =  new URL(manifestURI).openStream();
782
          inputStream.close();
783
          manifestURL = new URL(manifestURI);
784
        }
785
        catch (IOException exception)
786
        {
787
          // If the path isn't within the root of the archive, 
788
          // create a new URI for the folder location of the archive, 
789
          // so we can look in the folder that contains it.
790
          //
791
          uri = URI.createURI(uri.authority()).trimSegments(1);
792
        }
793
      }
794
              
795
      // If we didn't find the path in the usual place nor in the archive...
796
      //
797
      if (manifestURL == null)
798
      {
799
        // Trim off the "bin" or "runtime" segment.
800
        //
801
        String lastSegment = uri.lastSegment();
802
        if ("bin".equals(lastSegment) || "runtime".equals(lastSegment))
803
        {
804
          uri = uri.trimSegments(1);
805
        }
806
        uri = uri.appendSegments(relativePath);
807
        manifestURL = new URL(uri.toString());
808
      }
809
              
810
      if (manifestURL != null)
811
      {
812
        Manifest manifest = new Manifest(manifestURL.openStream());
813
        String symbolicName =  manifest.getMainAttributes().getValue("Bundle-SymbolicName");
814
        if (symbolicName != null)
815
        {
816
          int end = symbolicName.indexOf(";");
817
          if (end != -1)
818
          {
819
            symbolicName = symbolicName.substring(0, end);
820
          }
821
          System.out.println("Bundle-SymbolicName=" + symbolicName + " Bundle-Version=" + manifest.getMainAttributes().getValue("Bundle-Version"));
822
          return;
823
        }
824
      }
825
    }
826
    catch (Exception exception)
827
    {
828
    }
829
    
830
    System.err.println("No Bundle information found");
831
  }
832
}
7
}
(-)META-INF/MANIFEST.MF (-1 lines)
Lines 8-14 Link Here
8
Bundle-Vendor: %providerName
8
Bundle-Vendor: %providerName
9
Bundle-Localization: plugin
9
Bundle-Localization: plugin
10
Export-Package: org.eclipse.emf.common,
10
Export-Package: org.eclipse.emf.common,
11
 org.eclipse.emf.common.archive,
12
 org.eclipse.emf.common.command,
11
 org.eclipse.emf.common.command,
13
 org.eclipse.emf.common.notify,
12
 org.eclipse.emf.common.notify,
14
 org.eclipse.emf.common.notify.impl,
13
 org.eclipse.emf.common.notify.impl,
(-)src/org/eclipse/emf/common/EMFCommonLib.gwt.xml (+7 lines)
Added Link Here
1
<module>
2
	<!-- Inherit the core Web Toolkit stuff.                  -->
3
	<inherits name='com.google.gwt.user.User'/>
4
	<inherits name='org.eclipse.core.RuntimeCoreLib' />
5
6
	<source path="common" />
7
</module>

Return to bug 209434