1 /*
   2  * Copyright (c) 2016, 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 package jdk.dynalink.test;
  33 
  34 import java.security.AccessController;
  35 import java.security.PrivilegedAction;
  36 import java.util.ArrayList;
  37 import java.util.List;
  38 import java.util.regex.Matcher;
  39 import java.util.regex.Pattern;
  40 import jdk.dynalink.CallSiteDescriptor;
  41 import jdk.dynalink.NamedOperation;
  42 import jdk.dynalink.NamespaceOperation;
  43 import jdk.dynalink.Operation;
  44 import jdk.dynalink.StandardNamespace;
  45 import jdk.dynalink.StandardOperation;
  46 import jdk.dynalink.linker.GuardedInvocation;
  47 import jdk.dynalink.linker.GuardingDynamicLinker;
  48 import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
  49 import jdk.dynalink.linker.LinkRequest;
  50 import jdk.dynalink.linker.LinkerServices;
  51 import jdk.dynalink.linker.support.SimpleLinkRequest;
  52 
  53 /**
  54  * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276).
  55  * This linker translater underscore_separated method names to CamelCase names
  56  * used in Java APIs.
  57  */
  58 public final class TrustedUnderscoreNameLinkerExporter extends GuardingDynamicLinkerExporter {
  59     private static final Pattern UNDERSCORE_NAME = Pattern.compile("_(.)");
  60 
  61     // translate underscore_separated name as a CamelCase name
  62     private static String translateToCamelCase(final String name) {
  63         final Matcher m = UNDERSCORE_NAME.matcher(name);
  64         final StringBuilder buf = new StringBuilder();
  65         while (m.find()) {
  66             m.appendReplacement(buf, m.group(1).toUpperCase());
  67         }
  68         m.appendTail(buf);
  69         return buf.toString();
  70     }
  71 
  72     @Override
  73     public List<GuardingDynamicLinker> get() {
  74         final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
  75         linkers.add(new GuardingDynamicLinker() {
  76             @Override
  77             public GuardedInvocation getGuardedInvocation(final LinkRequest request,
  78                 final LinkerServices linkerServices) throws Exception {
  79                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
  80                 final Operation op = desc.getOperation();
  81                 final Object name = NamedOperation.getName(op);
  82                 final Operation namespaceOp = NamedOperation.getBaseOperation(op);
  83                 // is this a named GET_METHOD?
  84                 final boolean isGetMethod =
  85                         NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET
  86                         && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
  87                 if (isGetMethod && name instanceof String) {
  88                     final String str = (String)name;
  89                     if (str.indexOf('_') == -1) {
  90                         return null;
  91                     }
  92 
  93                     final String nameStr = translateToCamelCase(str);
  94                     // create a new call descriptor to use translated name
  95                     final CallSiteDescriptor newDesc = AccessController.doPrivileged(
  96                         new PrivilegedAction<CallSiteDescriptor>() {
  97                             @Override
  98                             public CallSiteDescriptor run() {
  99                                 return desc.changeOperation(((NamedOperation)op).changeName(nameStr));
 100                             }
 101                         });
 102                     // create a new Link request to link the call site with translated name
 103                     final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments());
 104                     // return guarded invocation linking the translated request
 105                     return linkerServices.getGuardedInvocation(newRequest);
 106                 }
 107 
 108                 return null;
 109             }
 110         });
 111         return linkers;
 112     }
 113 }