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