1 /*
   2  * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package com.sun.tools.javac.api;
  28 
  29 import java.io.File;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 import java.io.OutputStream;
  33 import java.io.Reader;
  34 import java.io.Writer;
  35 import java.lang.annotation.ElementType;
  36 import java.lang.annotation.Retention;
  37 import java.lang.annotation.RetentionPolicy;
  38 import java.lang.annotation.Target;
  39 import java.net.URI;
  40 import java.util.ArrayList;
  41 import java.util.Collection;
  42 import java.util.Collections;
  43 import java.util.HashMap;
  44 import java.util.Iterator;
  45 import java.util.List;
  46 import java.util.Locale;
  47 import java.util.Map;
  48 import java.util.Set;
  49 
  50 import javax.lang.model.element.Modifier;
  51 import javax.lang.model.element.NestingKind;
  52 import javax.tools.Diagnostic;
  53 import javax.tools.DiagnosticListener;
  54 import javax.tools.FileObject;
  55 import javax.tools.JavaFileManager;
  56 import javax.tools.JavaFileManager.Location;
  57 import javax.tools.JavaFileObject;
  58 import javax.tools.JavaFileObject.Kind;
  59 import javax.tools.StandardJavaFileManager;
  60 
  61 import com.sun.source.util.TaskEvent;
  62 import com.sun.source.util.TaskListener;
  63 import com.sun.tools.javac.util.ClientCodeException;
  64 import com.sun.tools.javac.util.Context;
  65 import com.sun.tools.javac.util.DefinedBy;
  66 import com.sun.tools.javac.util.DefinedBy.Api;
  67 import com.sun.tools.javac.util.JCDiagnostic;
  68 
  69 /**
  70  *  Wrap objects to enable unchecked exceptions to be caught and handled.
  71  *
  72  *  For each method, exceptions are handled as follows:
  73  *  <ul>
  74  *  <li>Checked exceptions are left alone and propogate upwards in the
  75  *      obvious way, since they are an expected aspect of the method's
  76  *      specification.
  77  *  <li>Unchecked exceptions which have already been caught and wrapped in
  78  *      ClientCodeException are left alone to continue propogating upwards.
  79  *  <li>All other unchecked exceptions (i.e. subtypes of RuntimeException
  80  *      and Error) and caught, and rethrown as a ClientCodeException with
  81  *      its cause set to the original exception.
  82  *  </ul>
  83  *
  84  *  The intent is that ClientCodeException can be caught at an appropriate point
  85  *  in the program and can be distinguished from any unanticipated unchecked
  86  *  exceptions arising in the main body of the code (i.e. bugs.) When the
  87  *  ClientCodeException has been caught, either a suitable message can be
  88  *  generated, or if appropriate, the original cause can be rethrown.
  89  *
  90  *  <p><b>This is NOT part of any supported API.
  91  *  If you write code that depends on this, you do so at your own risk.
  92  *  This code and its internal interfaces are subject to change or
  93  *  deletion without notice.</b>
  94  */
  95 public class ClientCodeWrapper {
  96     @Retention(RetentionPolicy.RUNTIME)
  97     @Target(ElementType.TYPE)
  98     public @interface Trusted { }
  99 
 100     public static ClientCodeWrapper instance(Context context) {
 101         ClientCodeWrapper instance = context.get(ClientCodeWrapper.class);
 102         if (instance == null)
 103             instance = new ClientCodeWrapper(context);
 104         return instance;
 105     }
 106 
 107     /**
 108      * A map to cache the results of whether or not a specific classes can
 109      * be "trusted", and thus does not need to be wrapped.
 110      */
 111     Map<Class<?>, Boolean> trustedClasses;
 112 
 113     protected ClientCodeWrapper(Context context) {
 114         trustedClasses = new HashMap<>();
 115     }
 116 
 117     public JavaFileManager wrap(JavaFileManager fm) {
 118         if (isTrusted(fm))
 119             return fm;
 120         if (fm instanceof StandardJavaFileManager)
 121             return new WrappedStandardJavaFileManager((StandardJavaFileManager) fm);
 122         return new WrappedJavaFileManager(fm);
 123     }
 124 
 125     public FileObject wrap(FileObject fo) {
 126         if (fo == null || isTrusted(fo))
 127             return fo;
 128         return new WrappedFileObject(fo);
 129     }
 130 
 131     FileObject unwrap(FileObject fo) {
 132         if (fo instanceof WrappedFileObject)
 133             return ((WrappedFileObject) fo).clientFileObject;
 134         else
 135             return fo;
 136     }
 137 
 138     public JavaFileObject wrap(JavaFileObject fo) {
 139         if (fo == null || isTrusted(fo))
 140             return fo;
 141         return new WrappedJavaFileObject(fo);
 142     }
 143 
 144     public Iterable<JavaFileObject> wrapJavaFileObjects(Iterable<? extends JavaFileObject> list) {
 145         List<JavaFileObject> wrapped = new ArrayList<>();
 146         for (JavaFileObject fo : list)
 147             wrapped.add(wrap(fo));
 148         return Collections.unmodifiableList(wrapped);
 149     }
 150 
 151     JavaFileObject unwrap(JavaFileObject fo) {
 152         if (fo instanceof WrappedJavaFileObject)
 153             return ((JavaFileObject) ((WrappedJavaFileObject) fo).clientFileObject);
 154         else
 155             return fo;
 156     }
 157 
 158     public <T /*super JavaFileOject*/> DiagnosticListener<T> wrap(DiagnosticListener<T> dl) {
 159         if (isTrusted(dl))
 160             return dl;
 161         return new WrappedDiagnosticListener<>(dl);
 162     }
 163 
 164     TaskListener wrap(TaskListener tl) {
 165         if (isTrusted(tl))
 166             return tl;
 167         return new WrappedTaskListener(tl);
 168     }
 169 
 170     TaskListener unwrap(TaskListener l) {
 171         if (l instanceof WrappedTaskListener)
 172             return ((WrappedTaskListener) l).clientTaskListener;
 173         else
 174             return l;
 175     }
 176 
 177     Collection<TaskListener> unwrap(Collection<? extends TaskListener> listeners) {
 178         Collection<TaskListener> c = new ArrayList<>(listeners.size());
 179         for (TaskListener l: listeners)
 180             c.add(unwrap(l));
 181         return c;
 182     }
 183 
 184     @SuppressWarnings("unchecked")
 185     private <T> Diagnostic<T> unwrap(final Diagnostic<T> diagnostic) {
 186         if (diagnostic instanceof JCDiagnostic) {
 187             JCDiagnostic d = (JCDiagnostic) diagnostic;
 188             return (Diagnostic<T>) new DiagnosticSourceUnwrapper(d);
 189         } else {
 190             return diagnostic;
 191         }
 192     }
 193 
 194     protected boolean isTrusted(Object o) {
 195         Class<?> c = o.getClass();
 196         Boolean trusted = trustedClasses.get(c);
 197         if (trusted == null) {
 198             trusted = c.getName().startsWith("com.sun.tools.javac.")
 199                     || c.isAnnotationPresent(Trusted.class);
 200             trustedClasses.put(c, trusted);
 201         }
 202         return trusted;
 203     }
 204 
 205     private String wrappedToString(Class<?> wrapperClass, Object wrapped) {
 206         return wrapperClass.getSimpleName() + "[" + wrapped + "]";
 207     }
 208 
 209     // <editor-fold defaultstate="collapsed" desc="Wrapper classes">
 210 
 211     protected class WrappedJavaFileManager implements JavaFileManager {
 212         protected JavaFileManager clientJavaFileManager;
 213         WrappedJavaFileManager(JavaFileManager clientJavaFileManager) {
 214             clientJavaFileManager.getClass(); // null check
 215             this.clientJavaFileManager = clientJavaFileManager;
 216         }
 217 
 218         @Override @DefinedBy(Api.COMPILER)
 219         public ClassLoader getClassLoader(Location location) {
 220             try {
 221                 return clientJavaFileManager.getClassLoader(location);
 222             } catch (ClientCodeException e) {
 223                 throw e;
 224             } catch (RuntimeException | Error e) {
 225                 throw new ClientCodeException(e);
 226             }
 227         }
 228 
 229         @Override @DefinedBy(Api.COMPILER)
 230         public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException {
 231             try {
 232                 return wrapJavaFileObjects(clientJavaFileManager.list(location, packageName, kinds, recurse));
 233             } catch (ClientCodeException e) {
 234                 throw e;
 235             } catch (RuntimeException | Error e) {
 236                 throw new ClientCodeException(e);
 237             }
 238         }
 239 
 240         @Override @DefinedBy(Api.COMPILER)
 241         public String inferBinaryName(Location location, JavaFileObject file) {
 242             try {
 243                 return clientJavaFileManager.inferBinaryName(location, unwrap(file));
 244             } catch (ClientCodeException e) {
 245                 throw e;
 246             } catch (RuntimeException | Error e) {
 247                 throw new ClientCodeException(e);
 248             }
 249         }
 250 
 251         @Override @DefinedBy(Api.COMPILER)
 252         public boolean isSameFile(FileObject a, FileObject b) {
 253             try {
 254                 return clientJavaFileManager.isSameFile(unwrap(a), unwrap(b));
 255             } catch (ClientCodeException e) {
 256                 throw e;
 257             } catch (RuntimeException | Error e) {
 258                 throw new ClientCodeException(e);
 259             }
 260         }
 261 
 262         @Override @DefinedBy(Api.COMPILER)
 263         public boolean handleOption(String current, Iterator<String> remaining) {
 264             try {
 265                 return clientJavaFileManager.handleOption(current, remaining);
 266             } catch (ClientCodeException e) {
 267                 throw e;
 268             } catch (RuntimeException | Error e) {
 269                 throw new ClientCodeException(e);
 270             }
 271         }
 272 
 273         @Override @DefinedBy(Api.COMPILER)
 274         public boolean hasLocation(Location location) {
 275             try {
 276                 return clientJavaFileManager.hasLocation(location);
 277             } catch (ClientCodeException e) {
 278                 throw e;
 279             } catch (RuntimeException | Error e) {
 280                 throw new ClientCodeException(e);
 281             }
 282         }
 283 
 284         @Override @DefinedBy(Api.COMPILER)
 285         public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
 286             try {
 287                 return wrap(clientJavaFileManager.getJavaFileForInput(location, className, kind));
 288             } catch (ClientCodeException e) {
 289                 throw e;
 290             } catch (RuntimeException | Error e) {
 291                 throw new ClientCodeException(e);
 292             }
 293         }
 294 
 295         @Override @DefinedBy(Api.COMPILER)
 296         public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
 297             try {
 298                 return wrap(clientJavaFileManager.getJavaFileForOutput(location, className, kind, unwrap(sibling)));
 299             } catch (ClientCodeException e) {
 300                 throw e;
 301             } catch (RuntimeException | Error e) {
 302                 throw new ClientCodeException(e);
 303             }
 304         }
 305 
 306         @Override @DefinedBy(Api.COMPILER)
 307         public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
 308             try {
 309                 return wrap(clientJavaFileManager.getFileForInput(location, packageName, relativeName));
 310             } catch (ClientCodeException e) {
 311                 throw e;
 312             } catch (RuntimeException | Error e) {
 313                 throw new ClientCodeException(e);
 314             }
 315         }
 316 
 317         @Override @DefinedBy(Api.COMPILER)
 318         public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
 319             try {
 320                 return wrap(clientJavaFileManager.getFileForOutput(location, packageName, relativeName, unwrap(sibling)));
 321             } catch (ClientCodeException e) {
 322                 throw e;
 323             } catch (RuntimeException | Error e) {
 324                 throw new ClientCodeException(e);
 325             }
 326         }
 327 
 328         @Override @DefinedBy(Api.COMPILER)
 329         public void flush() throws IOException {
 330             try {
 331                 clientJavaFileManager.flush();
 332             } catch (ClientCodeException e) {
 333                 throw e;
 334             } catch (RuntimeException | Error e) {
 335                 throw new ClientCodeException(e);
 336             }
 337         }
 338 
 339         @Override @DefinedBy(Api.COMPILER)
 340         public void close() throws IOException {
 341             try {
 342                 clientJavaFileManager.close();
 343             } catch (ClientCodeException e) {
 344                 throw e;
 345             } catch (RuntimeException | Error e) {
 346                 throw new ClientCodeException(e);
 347             }
 348         }
 349 
 350         @Override @DefinedBy(Api.COMPILER)
 351         public int isSupportedOption(String option) {
 352             try {
 353                 return clientJavaFileManager.isSupportedOption(option);
 354             } catch (ClientCodeException e) {
 355                 throw e;
 356             } catch (RuntimeException | Error e) {
 357                 throw new ClientCodeException(e);
 358             }
 359         }
 360 
 361         @Override
 362         public String toString() {
 363             return wrappedToString(getClass(), clientJavaFileManager);
 364         }
 365     }
 366 
 367     protected class WrappedStandardJavaFileManager extends WrappedJavaFileManager
 368             implements StandardJavaFileManager {
 369         WrappedStandardJavaFileManager(StandardJavaFileManager clientJavaFileManager) {
 370             super(clientJavaFileManager);
 371         }
 372 
 373         @Override @DefinedBy(Api.COMPILER)
 374         public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
 375             try {
 376                 return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjectsFromFiles(files);
 377             } catch (ClientCodeException e) {
 378                 throw e;
 379             } catch (RuntimeException | Error e) {
 380                 throw new ClientCodeException(e);
 381             }
 382         }
 383 
 384         @Override @DefinedBy(Api.COMPILER)
 385         public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
 386             try {
 387                 return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjects(files);
 388             } catch (ClientCodeException e) {
 389                 throw e;
 390             } catch (RuntimeException | Error e) {
 391                 throw new ClientCodeException(e);
 392             }
 393         }
 394 
 395         @Override @DefinedBy(Api.COMPILER)
 396         public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
 397             try {
 398                 return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjectsFromStrings(names);
 399             } catch (ClientCodeException e) {
 400                 throw e;
 401             } catch (RuntimeException | Error e) {
 402                 throw new ClientCodeException(e);
 403             }
 404         }
 405 
 406         @Override @DefinedBy(Api.COMPILER)
 407         public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
 408             try {
 409                 return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjects(names);
 410             } catch (ClientCodeException e) {
 411                 throw e;
 412             } catch (RuntimeException | Error e) {
 413                 throw new ClientCodeException(e);
 414             }
 415         }
 416 
 417         @Override @DefinedBy(Api.COMPILER)
 418         public void setLocation(Location location, Iterable<? extends File> path) throws IOException {
 419             try {
 420                 ((StandardJavaFileManager)clientJavaFileManager).setLocation(location, path);
 421             } catch (ClientCodeException e) {
 422                 throw e;
 423             } catch (RuntimeException | Error e) {
 424                 throw new ClientCodeException(e);
 425             }
 426         }
 427 
 428         @Override @DefinedBy(Api.COMPILER)
 429         public Iterable<? extends File> getLocation(Location location) {
 430             try {
 431                 return ((StandardJavaFileManager)clientJavaFileManager).getLocation(location);
 432             } catch (ClientCodeException e) {
 433                 throw e;
 434             } catch (RuntimeException | Error e) {
 435                 throw new ClientCodeException(e);
 436             }
 437         }
 438     }
 439 
 440     protected class WrappedFileObject implements FileObject {
 441         protected FileObject clientFileObject;
 442         WrappedFileObject(FileObject clientFileObject) {
 443             clientFileObject.getClass(); // null check
 444             this.clientFileObject = clientFileObject;
 445         }
 446 
 447         @Override @DefinedBy(Api.COMPILER)
 448         public URI toUri() {
 449             try {
 450                 return clientFileObject.toUri();
 451             } catch (ClientCodeException e) {
 452                 throw e;
 453             } catch (RuntimeException | Error e) {
 454                 throw new ClientCodeException(e);
 455             }
 456         }
 457 
 458         @Override @DefinedBy(Api.COMPILER)
 459         public String getName() {
 460             try {
 461                 return clientFileObject.getName();
 462             } catch (ClientCodeException e) {
 463                 throw e;
 464             } catch (RuntimeException | Error e) {
 465                 throw new ClientCodeException(e);
 466             }
 467         }
 468 
 469         @Override @DefinedBy(Api.COMPILER)
 470         public InputStream openInputStream() throws IOException {
 471             try {
 472                 return clientFileObject.openInputStream();
 473             } catch (ClientCodeException e) {
 474                 throw e;
 475             } catch (RuntimeException | Error e) {
 476                 throw new ClientCodeException(e);
 477             }
 478         }
 479 
 480         @Override @DefinedBy(Api.COMPILER)
 481         public OutputStream openOutputStream() throws IOException {
 482             try {
 483                 return clientFileObject.openOutputStream();
 484             } catch (ClientCodeException e) {
 485                 throw e;
 486             } catch (RuntimeException | Error e) {
 487                 throw new ClientCodeException(e);
 488             }
 489         }
 490 
 491         @Override @DefinedBy(Api.COMPILER)
 492         public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
 493             try {
 494                 return clientFileObject.openReader(ignoreEncodingErrors);
 495             } catch (ClientCodeException e) {
 496                 throw e;
 497             } catch (RuntimeException | Error e) {
 498                 throw new ClientCodeException(e);
 499             }
 500         }
 501 
 502         @Override @DefinedBy(Api.COMPILER)
 503         public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
 504             try {
 505                 return clientFileObject.getCharContent(ignoreEncodingErrors);
 506             } catch (ClientCodeException e) {
 507                 throw e;
 508             } catch (RuntimeException | Error e) {
 509                 throw new ClientCodeException(e);
 510             }
 511         }
 512 
 513         @Override @DefinedBy(Api.COMPILER)
 514         public Writer openWriter() throws IOException {
 515             try {
 516                 return clientFileObject.openWriter();
 517             } catch (ClientCodeException e) {
 518                 throw e;
 519             } catch (RuntimeException | Error e) {
 520                 throw new ClientCodeException(e);
 521             }
 522         }
 523 
 524         @Override @DefinedBy(Api.COMPILER)
 525         public long getLastModified() {
 526             try {
 527                 return clientFileObject.getLastModified();
 528             } catch (ClientCodeException e) {
 529                 throw e;
 530             } catch (RuntimeException | Error e) {
 531                 throw new ClientCodeException(e);
 532             }
 533         }
 534 
 535         @Override @DefinedBy(Api.COMPILER)
 536         public boolean delete() {
 537             try {
 538                 return clientFileObject.delete();
 539             } catch (ClientCodeException e) {
 540                 throw e;
 541             } catch (RuntimeException | Error e) {
 542                 throw new ClientCodeException(e);
 543             }
 544         }
 545 
 546         @Override
 547         public String toString() {
 548             return wrappedToString(getClass(), clientFileObject);
 549         }
 550     }
 551 
 552     protected class WrappedJavaFileObject extends WrappedFileObject implements JavaFileObject {
 553         WrappedJavaFileObject(JavaFileObject clientJavaFileObject) {
 554             super(clientJavaFileObject);
 555         }
 556 
 557         @Override @DefinedBy(Api.COMPILER)
 558         public Kind getKind() {
 559             try {
 560                 return ((JavaFileObject)clientFileObject).getKind();
 561             } catch (ClientCodeException e) {
 562                 throw e;
 563             } catch (RuntimeException | Error e) {
 564                 throw new ClientCodeException(e);
 565             }
 566         }
 567 
 568         @Override @DefinedBy(Api.COMPILER)
 569         public boolean isNameCompatible(String simpleName, Kind kind) {
 570             try {
 571                 return ((JavaFileObject)clientFileObject).isNameCompatible(simpleName, kind);
 572             } catch (ClientCodeException e) {
 573                 throw e;
 574             } catch (RuntimeException | Error e) {
 575                 throw new ClientCodeException(e);
 576             }
 577         }
 578 
 579         @Override @DefinedBy(Api.COMPILER)
 580         public NestingKind getNestingKind() {
 581             try {
 582                 return ((JavaFileObject)clientFileObject).getNestingKind();
 583             } catch (ClientCodeException e) {
 584                 throw e;
 585             } catch (RuntimeException | Error e) {
 586                 throw new ClientCodeException(e);
 587             }
 588         }
 589 
 590         @Override @DefinedBy(Api.COMPILER)
 591         public Modifier getAccessLevel() {
 592             try {
 593                 return ((JavaFileObject)clientFileObject).getAccessLevel();
 594             } catch (ClientCodeException e) {
 595                 throw e;
 596             } catch (RuntimeException | Error e) {
 597                 throw new ClientCodeException(e);
 598             }
 599         }
 600 
 601         @Override
 602         public String toString() {
 603             return wrappedToString(getClass(), clientFileObject);
 604         }
 605     }
 606 
 607     protected class WrappedDiagnosticListener<T /*super JavaFileObject*/> implements DiagnosticListener<T> {
 608         protected DiagnosticListener<T> clientDiagnosticListener;
 609         WrappedDiagnosticListener(DiagnosticListener<T> clientDiagnosticListener) {
 610             clientDiagnosticListener.getClass(); // null check
 611             this.clientDiagnosticListener = clientDiagnosticListener;
 612         }
 613 
 614         @Override @DefinedBy(Api.COMPILER)
 615         public void report(Diagnostic<? extends T> diagnostic) {
 616             try {
 617                 clientDiagnosticListener.report(unwrap(diagnostic));
 618             } catch (ClientCodeException e) {
 619                 throw e;
 620             } catch (RuntimeException | Error e) {
 621                 throw new ClientCodeException(e);
 622             }
 623         }
 624 
 625         @Override
 626         public String toString() {
 627             return wrappedToString(getClass(), clientDiagnosticListener);
 628         }
 629     }
 630 
 631     public class DiagnosticSourceUnwrapper implements Diagnostic<JavaFileObject> {
 632         public final JCDiagnostic d;
 633 
 634         DiagnosticSourceUnwrapper(JCDiagnostic d) {
 635             this.d = d;
 636         }
 637 
 638         @Override @DefinedBy(Api.COMPILER)
 639         public Diagnostic.Kind getKind() {
 640             return d.getKind();
 641         }
 642 
 643         @Override @DefinedBy(Api.COMPILER)
 644         public JavaFileObject getSource() {
 645             return unwrap(d.getSource());
 646         }
 647 
 648         @Override @DefinedBy(Api.COMPILER)
 649         public long getPosition() {
 650             return d.getPosition();
 651         }
 652 
 653         @Override @DefinedBy(Api.COMPILER)
 654         public long getStartPosition() {
 655             return d.getStartPosition();
 656         }
 657 
 658         @Override @DefinedBy(Api.COMPILER)
 659         public long getEndPosition() {
 660             return d.getEndPosition();
 661         }
 662 
 663         @Override @DefinedBy(Api.COMPILER)
 664         public long getLineNumber() {
 665             return d.getLineNumber();
 666         }
 667 
 668         @Override @DefinedBy(Api.COMPILER)
 669         public long getColumnNumber() {
 670             return d.getColumnNumber();
 671         }
 672 
 673         @Override @DefinedBy(Api.COMPILER)
 674         public String getCode() {
 675             return d.getCode();
 676         }
 677 
 678         @Override @DefinedBy(Api.COMPILER)
 679         public String getMessage(Locale locale) {
 680             return d.getMessage(locale);
 681         }
 682 
 683         @Override
 684         public String toString() {
 685             return d.toString();
 686         }
 687     }
 688 
 689     protected class WrappedTaskListener implements TaskListener {
 690         protected TaskListener clientTaskListener;
 691         WrappedTaskListener(TaskListener clientTaskListener) {
 692             clientTaskListener.getClass(); // null check
 693             this.clientTaskListener = clientTaskListener;
 694         }
 695 
 696         @Override @DefinedBy(Api.COMPILER_TREE)
 697         public void started(TaskEvent ev) {
 698             try {
 699                 clientTaskListener.started(ev);
 700             } catch (ClientCodeException e) {
 701                 throw e;
 702             } catch (RuntimeException | Error e) {
 703                 throw new ClientCodeException(e);
 704             }
 705         }
 706 
 707         @Override @DefinedBy(Api.COMPILER_TREE)
 708         public void finished(TaskEvent ev) {
 709             try {
 710                 clientTaskListener.finished(ev);
 711             } catch (ClientCodeException e) {
 712                 throw e;
 713             } catch (RuntimeException | Error e) {
 714                 throw new ClientCodeException(e);
 715             }
 716         }
 717 
 718         @Override
 719         public String toString() {
 720             return wrappedToString(getClass(), clientTaskListener);
 721         }
 722     }
 723 
 724     // </editor-fold>
 725 }