nashorn/samples/UnderscoreNameLinkerExporter.java
changeset 34455 cc9f05d3caf0
equal deleted inserted replaced
34454:735fec4e8ee8 34455:cc9f05d3caf0
       
     1 /*
       
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Oracle nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 import java.lang.invoke.MethodHandle;
       
    33 import java.lang.invoke.MethodHandles;
       
    34 import java.lang.invoke.MethodType;
       
    35 import java.util.ArrayList;
       
    36 import java.util.List;
       
    37 import java.util.regex.Pattern;
       
    38 import java.util.regex.Matcher;
       
    39 import jdk.dynalink.CallSiteDescriptor;
       
    40 import jdk.dynalink.CompositeOperation;
       
    41 import jdk.dynalink.NamedOperation;
       
    42 import jdk.dynalink.Operation;
       
    43 import jdk.dynalink.CompositeOperation;
       
    44 import jdk.dynalink.StandardOperation;
       
    45 import jdk.dynalink.linker.GuardingDynamicLinker;
       
    46 import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
       
    47 import jdk.dynalink.linker.GuardedInvocation;
       
    48 import jdk.dynalink.linker.LinkRequest;
       
    49 import jdk.dynalink.linker.LinkerServices;
       
    50 import jdk.dynalink.linker.support.SimpleLinkRequest;
       
    51 
       
    52 /**
       
    53  * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276).
       
    54  * This linker translater underscore_separated method names to CamelCase names
       
    55  * used in Java APIs.
       
    56  */
       
    57 public final class UnderscoreNameLinkerExporter extends GuardingDynamicLinkerExporter {
       
    58     static {
       
    59         System.out.println("pluggable dynalink underscore name linker loaded");
       
    60     }
       
    61 
       
    62     private static final Pattern UNDERSCORE_NAME = Pattern.compile("_(.)");
       
    63 
       
    64     // translate underscore_separated name as a CamelCase name
       
    65     private static String translateToCamelCase(String name) {
       
    66         Matcher m = UNDERSCORE_NAME.matcher(name);
       
    67         StringBuilder buf = new StringBuilder();
       
    68         while (m.find()) {
       
    69             m.appendReplacement(buf, m.group(1).toUpperCase());
       
    70         }
       
    71         m.appendTail(buf);
       
    72         return buf.toString();
       
    73     }
       
    74 
       
    75     // locate the first standard operation from the call descriptor
       
    76     private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
       
    77         final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
       
    78         if (base instanceof StandardOperation) {
       
    79             return (StandardOperation)base;
       
    80         } else if (base instanceof CompositeOperation) {
       
    81             final CompositeOperation cop = (CompositeOperation)base;
       
    82             for(int i = 0; i < cop.getOperationCount(); ++i) {
       
    83                 final Operation op = cop.getOperation(i);
       
    84                 if (op instanceof StandardOperation) {
       
    85                     return (StandardOperation)op;
       
    86                 }
       
    87             }
       
    88         }
       
    89         return null;
       
    90     }
       
    91 
       
    92     @Override
       
    93     public List<GuardingDynamicLinker> get() {
       
    94         final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
       
    95         linkers.add(new GuardingDynamicLinker() {
       
    96             @Override
       
    97             public GuardedInvocation getGuardedInvocation(LinkRequest request,
       
    98                 LinkerServices linkerServices) throws Exception {
       
    99                 final Object self = request.getReceiver();
       
   100                 CallSiteDescriptor desc = request.getCallSiteDescriptor();
       
   101                 Operation op = desc.getOperation();
       
   102                 Object name = NamedOperation.getName(op);
       
   103                 // is this a named GET_METHOD?
       
   104                 boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD;
       
   105                 if (isGetMethod && name instanceof String) {
       
   106                     String str = (String)name;
       
   107                     if (str.indexOf('_') == -1) {
       
   108                         return null;
       
   109                     }
       
   110 
       
   111                     String nameStr = translateToCamelCase(str);
       
   112                     // create a new call descriptor to use translated name
       
   113                     CallSiteDescriptor newDesc = new CallSiteDescriptor(
       
   114                         desc.getLookup(),
       
   115                         new NamedOperation(NamedOperation.getBaseOperation(op), nameStr),
       
   116                         desc.getMethodType());
       
   117                     // create a new Link request to link the call site with translated name
       
   118                     LinkRequest newRequest = new SimpleLinkRequest(newDesc,
       
   119                         request.isCallSiteUnstable(), request.getArguments());
       
   120                     // return guarded invocation linking the translated request
       
   121                     return linkerServices.getGuardedInvocation(newRequest);
       
   122                 }
       
   123 
       
   124                 return null;
       
   125             }
       
   126         });
       
   127         return linkers;
       
   128     }
       
   129 }