001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.tang.implementation.protobuf; 020 021import org.apache.reef.tang.ClassHierarchy; 022import org.apache.reef.tang.exceptions.BindException; 023import org.apache.reef.tang.exceptions.NameResolutionException; 024import org.apache.reef.tang.implementation.Constructor; 025import org.apache.reef.tang.implementation.InjectionPlan; 026import org.apache.reef.tang.implementation.Subplan; 027import org.apache.reef.tang.implementation.java.JavaInstance; 028import org.apache.reef.tang.proto.InjectionPlanProto; 029import org.apache.reef.tang.types.ClassNode; 030import org.apache.reef.tang.types.ConstructorDef; 031import org.apache.reef.tang.types.Node; 032 033import java.util.Arrays; 034import java.util.List; 035 036public class ProtocolBufferInjectionPlan { 037 038 <T> InjectionPlanProto.InjectionPlan newConstructor(final String fullName, 039 List<InjectionPlanProto.InjectionPlan> plans) { 040 return InjectionPlanProto.InjectionPlan 041 .newBuilder() 042 .setName(fullName) 043 .setConstructor( 044 InjectionPlanProto.Constructor.newBuilder().addAllArgs(plans) 045 .build()).build(); 046 } 047 048 <T> InjectionPlanProto.InjectionPlan newSubplan(final String fullName, 049 int selectedPlan, List<InjectionPlanProto.InjectionPlan> plans) { 050 return InjectionPlanProto.InjectionPlan 051 .newBuilder() 052 .setName(fullName) 053 .setSubplan( 054 InjectionPlanProto.Subplan.newBuilder() 055 .setSelectedPlan(selectedPlan).addAllPlans(plans).build()) 056 .build(); 057 } 058 059 <T> InjectionPlanProto.InjectionPlan newInstance(final String fullName, 060 final String value) { 061 return InjectionPlanProto.InjectionPlan.newBuilder().setName(fullName) 062 .setInstance(InjectionPlanProto.Instance.newBuilder().setValue(value)) 063 .build(); 064 } 065 066 public <T> InjectionPlanProto.InjectionPlan serialize(InjectionPlan<T> ip) { 067 if (ip instanceof Constructor) { 068 Constructor<T> cons = (Constructor<T>) ip; 069 InjectionPlan<?>[] args = cons.getArgs(); 070 InjectionPlanProto.InjectionPlan[] protoArgs = new InjectionPlanProto.InjectionPlan[args.length]; 071 for (int i = 0; i < args.length; i++) { 072 protoArgs[i] = serialize(args[i]); 073 } 074 return newConstructor(ip.getNode().getFullName(), 075 Arrays.asList(protoArgs)); 076 } else if (ip instanceof Subplan) { 077 Subplan<T> sp = (Subplan<T>) ip; 078 InjectionPlan<?>[] args = sp.getPlans(); 079 InjectionPlanProto.InjectionPlan[] subPlans = new InjectionPlanProto.InjectionPlan[args.length]; 080 for (int i = 0; i < args.length; i++) { 081 subPlans[i] = serialize(args[i]); 082 } 083 return newSubplan(ip.getNode().getFullName(), sp.getSelectedIndex(), 084 Arrays.asList(subPlans)); 085 } else if (ip instanceof JavaInstance) { 086 JavaInstance<T> ji = (JavaInstance<T>) ip; 087 return newInstance(ip.getNode().getFullName(), ji.getInstanceAsString()); 088 } else { 089 throw new IllegalStateException( 090 "Encountered unknown type of InjectionPlan: " + ip); 091 } 092 } 093 094 private Object parse(String type, String value) { 095 // XXX this is a placeholder for now. We need a parser API that will 096 // either produce a live java object or (partially) validate stuff to 097 // see if it looks like the target language will be able to handle this 098 // type + value. 099 return value; 100 } 101 102 @SuppressWarnings("unchecked") 103 public <T> InjectionPlan<T> deserialize(ClassHierarchy ch, 104 InjectionPlanProto.InjectionPlan ip) throws NameResolutionException, 105 BindException { 106 final String fullName = ip.getName(); 107 if (ip.hasConstructor()) { 108 final InjectionPlanProto.Constructor cons = ip.getConstructor(); 109 110 final ClassNode<T> cn = (ClassNode<T>) ch.getNode(fullName); 111 112 final InjectionPlanProto.InjectionPlan protoBufArgs[] = cons 113 .getArgsList().toArray(new InjectionPlanProto.InjectionPlan[0]); 114 final ClassNode<?>[] cnArgs = new ClassNode[protoBufArgs.length]; 115 116 for (int i = 0; i < protoBufArgs.length; i++) { 117 cnArgs[i] = (ClassNode<?>) ch.getNode(protoBufArgs[i].getName()); 118 } 119 120 final InjectionPlan<?> ipArgs[] = new InjectionPlan[protoBufArgs.length]; 121 122 for (int i = 0; i < protoBufArgs.length; i++) { 123 ipArgs[i] = (InjectionPlan<?>) deserialize(ch, protoBufArgs[i]); 124 } 125 126 final ConstructorDef<T> constructor = cn.getConstructorDef(cnArgs); 127 return new Constructor<T>(cn, constructor, ipArgs); 128 } else if (ip.hasInstance()) { 129 InjectionPlanProto.Instance ins = ip.getInstance(); 130 T instance = (T) parse(ip.getName(), ins.getValue()); 131 return new JavaInstance<T>(ch.getNode(ip.getName()), instance); 132 } else if (ip.hasSubplan()) { 133 final InjectionPlanProto.Subplan subplan = ip.getSubplan(); 134 final InjectionPlanProto.InjectionPlan protoBufPlans[] = subplan 135 .getPlansList().toArray(new InjectionPlanProto.InjectionPlan[0]); 136 137 final InjectionPlan<T> subPlans[] = new InjectionPlan[protoBufPlans.length]; 138 for (int i = 0; i < protoBufPlans.length; i++) { 139 subPlans[i] = (InjectionPlan<T>) deserialize(ch, protoBufPlans[i]); 140 } 141 Node n = ch.getNode(fullName); 142 return new Subplan<T>(n, subPlans); 143 } else { 144 throw new IllegalStateException( 145 "Encountered unknown type of injection plan: " + ip); 146 } 147 } 148}