org.chromium.debug.core/src/org/chromium/debug/core/SourceNameMapperContainer.java
changeset 355 8726e95bcbba
equal deleted inserted replaced
354:0bceeb415e7f 355:8726e95bcbba
       
     1 package org.chromium.debug.core;
       
     2 
       
     3 import org.eclipse.core.runtime.CoreException;
       
     4 import org.eclipse.core.runtime.IStatus;
       
     5 import org.eclipse.core.runtime.Status;
       
     6 import org.eclipse.debug.core.DebugPlugin;
       
     7 import org.eclipse.debug.core.sourcelookup.ISourceContainer;
       
     8 import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
       
     9 import org.eclipse.debug.core.sourcelookup.ISourceContainerTypeDelegate;
       
    10 import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
       
    11 import org.eclipse.osgi.util.NLS;
       
    12 
       
    13 /**
       
    14  * A special type of container that translates names of the source and delegates lookup
       
    15  * to another source container.
       
    16  * This could be useful when JS resource name is like "http://localhost/scripts/util.js"; such
       
    17  * source name could be converted into "scripts/util.js".
       
    18  * Currently container supports only prefix-based translation: if source name starts with a prefix,
       
    19  * the prefix is truncated; otherwise the source name is discarded.
       
    20  */
       
    21 public class SourceNameMapperContainer implements ISourceContainer {
       
    22 
       
    23   private static final String TYPE_ID =
       
    24       "org.chromium.debug.core.SourceNameMapperContainer.type"; //$NON-NLS-1$
       
    25 
       
    26   private final ISourceContainer targetContainer;
       
    27   private final String prefix;
       
    28 
       
    29   public SourceNameMapperContainer(String prefix, ISourceContainer targetContainer) {
       
    30     this.targetContainer = targetContainer;
       
    31     this.prefix = prefix;
       
    32   }
       
    33 
       
    34   public void dispose() {
       
    35   }
       
    36 
       
    37   public String getPrefix() {
       
    38     return prefix;
       
    39   }
       
    40 
       
    41   public ISourceContainer getTargetContainer() {
       
    42     return targetContainer;
       
    43   }
       
    44 
       
    45   public Object[] findSourceElements(String name) throws CoreException {
       
    46     if (!name.startsWith(prefix)) {
       
    47       return new Object[0];
       
    48     }
       
    49     String shortName = name.substring(prefix.length());
       
    50     return targetContainer.findSourceElements(shortName);
       
    51   }
       
    52 
       
    53 
       
    54   public String getName() {
       
    55     return NLS.bind(Messages.SourceNameMapperContainer_NAME, prefix);
       
    56   }
       
    57 
       
    58 
       
    59   public ISourceContainer[] getSourceContainers() {
       
    60     return new ISourceContainer[] { targetContainer };
       
    61   }
       
    62 
       
    63 
       
    64   public ISourceContainerType getType() {
       
    65     return DebugPlugin.getDefault().getLaunchManager().getSourceContainerType(TYPE_ID);
       
    66   }
       
    67 
       
    68 
       
    69   public void init(ISourceLookupDirector director) {
       
    70   }
       
    71 
       
    72 
       
    73   public boolean isComposite() {
       
    74     return true;
       
    75   }
       
    76 
       
    77   private String getMemento() throws CoreException {
       
    78     StringBuilder builder = new StringBuilder();
       
    79     MementoFormat.encodeComponent(prefix, builder);
       
    80     MementoFormat.encodeComponent(targetContainer.getType().getId(), builder);
       
    81     MementoFormat.encodeComponent(targetContainer.getType().getMemento(targetContainer), builder);
       
    82     return builder.toString();
       
    83   }
       
    84 
       
    85 
       
    86   public Object getAdapter(Class adapter) {
       
    87     return null;
       
    88   }
       
    89 
       
    90   /**
       
    91    * A type delegate that serializes/deserializes container instances into/from memento.
       
    92    */
       
    93   public static class TypeDelegate implements ISourceContainerTypeDelegate {
       
    94     public ISourceContainer createSourceContainer(String memento) throws CoreException {
       
    95       MementoFormat.Parser parser = new MementoFormat.Parser(memento);
       
    96       String prefix;
       
    97       String typeId;
       
    98       String subContainerMemento;
       
    99       try {
       
   100         prefix = parser.nextComponent();
       
   101         typeId = parser.nextComponent();
       
   102         subContainerMemento = parser.nextComponent();
       
   103       } catch (MementoFormat.ParserException e) {
       
   104         throw new CoreException(new Status(IStatus.ERROR,
       
   105             ChromiumDebugPlugin.PLUGIN_ID, "Failed to parse memento", e)); //$NON-NLS-1$
       
   106       }
       
   107       ISourceContainerType subContainerType =
       
   108           DebugPlugin.getDefault().getLaunchManager().getSourceContainerType(typeId);
       
   109       ISourceContainer subContainer = subContainerType.createSourceContainer(subContainerMemento);
       
   110       return new SourceNameMapperContainer(prefix, subContainer);
       
   111     }
       
   112 
       
   113     public String getMemento(ISourceContainer container) throws CoreException {
       
   114       SourceNameMapperContainer chromeContainer = (SourceNameMapperContainer) container;
       
   115       return chromeContainer.getMemento();
       
   116     }
       
   117   }
       
   118 
       
   119   /**
       
   120    * Handles memento string format. The format is just a sequence of strings that are preceded
       
   121    * with their lengths and decorated with parentheses to make it more human-readable.
       
   122    */
       
   123   private static class MementoFormat {
       
   124 
       
   125     static void encodeComponent(String component, StringBuilder output) {
       
   126       output.append(component.length());
       
   127       output.append('(').append(component).append(')');
       
   128     }
       
   129 
       
   130     /**
       
   131      * A simple parser that reads char sequence as a sequence of strings.
       
   132      */
       
   133     static class Parser {
       
   134       private final CharSequence charSequence;
       
   135       private int pos = 0;
       
   136       Parser(CharSequence charSequence) {
       
   137         this.charSequence = charSequence;
       
   138       }
       
   139       String nextComponent() throws ParserException {
       
   140         if (pos >= charSequence.length()) {
       
   141           throw new ParserException("Unexpected end of line"); //$NON-NLS-1$
       
   142         }
       
   143         char ch = charSequence.charAt(pos);
       
   144         pos++;
       
   145         int num = Character.digit(ch, 10);
       
   146         if (num == -1) {
       
   147           throw new ParserException("Digit expected"); //$NON-NLS-1$
       
   148         }
       
   149         int len = num;
       
   150         while (true) {
       
   151           if (pos >= charSequence.length()) {
       
   152             throw new ParserException("Unexpected end of line"); //$NON-NLS-1$
       
   153           }
       
   154           ch = charSequence.charAt(pos);
       
   155           if (!Character.isDigit(ch)) {
       
   156             break;
       
   157           }
       
   158           pos++;
       
   159           num = Character.digit(ch, 10);
       
   160           if (num == -1) {
       
   161             throw new ParserException("Digit expected"); //$NON-NLS-1$
       
   162           }
       
   163           len = len * 10 + num;
       
   164         }
       
   165         pos++;
       
   166         if (pos + len + 1 > charSequence.length()) {
       
   167           throw new ParserException("Unexpected end of line"); //$NON-NLS-1$
       
   168         }
       
   169         String result = charSequence.subSequence(pos, pos + len).toString();
       
   170         pos += len + 1;
       
   171         return result;
       
   172       }
       
   173     }
       
   174     private static class ParserException extends Exception {
       
   175       ParserException() {
       
   176       }
       
   177       ParserException(String message, Throwable cause) {
       
   178         super(message, cause);
       
   179       }
       
   180       ParserException(String message) {
       
   181         super(message);
       
   182       }
       
   183       ParserException(Throwable cause) {
       
   184         super(cause);
       
   185       }
       
   186     }
       
   187   }
       
   188 }