001/* 002 * Copyright 2017 the original author or authors. 003 * 004 * Licensed to the Apache Software Foundation (ASF) under one or more 005 * contributor license agreements. See the NOTICE file distributed with 006 * this work for additional information regarding copyright ownership. 007 * The ASF licenses this file to You under the Apache License, Version 2.0 008 * (the "License"); you may not use this file except in compliance with 009 * the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package net.sf.jkniv.camel.sap.jco3; 020 021import java.time.Duration; 022import java.time.Instant; 023import java.time.LocalDate; 024import java.time.LocalDateTime; 025import java.time.LocalTime; 026import java.util.ArrayList; 027import java.util.Calendar; 028import java.util.Date; 029import java.util.HashMap; 030import java.util.HashSet; 031import java.util.Iterator; 032import java.util.List; 033import java.util.Map; 034import java.util.Map.Entry; 035import java.util.Set; 036 037import org.apache.camel.Exchange; 038import org.apache.camel.RuntimeCamelException; 039import org.apache.camel.impl.DefaultProducer; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043import com.sap.conn.jco.JCoDestination; 044import com.sap.conn.jco.JCoDestinationManager; 045import com.sap.conn.jco.JCoField; 046import com.sap.conn.jco.JCoFieldIterator; 047import com.sap.conn.jco.JCoFunction; 048import com.sap.conn.jco.JCoStructure; 049import com.sap.conn.jco.JCoTable; 050 051/** 052 * Supports communication with the SAP Server in inbound calls (Java calls ABAP) using JCo. 053 * 054 */ 055public class SapJcoProducer extends DefaultProducer 056{ 057 private static final Logger LOG = LoggerFactory.getLogger(SapJcoProducer.class); 058 private SapJcoEndpoint endpoint; 059 private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<Class<?>>(); 060 static 061 { 062 SUPPORTED_TYPES.add(String.class); 063 SUPPORTED_TYPES.add(boolean.class); 064 SUPPORTED_TYPES.add(char.class); 065 SUPPORTED_TYPES.add(byte.class); 066 SUPPORTED_TYPES.add(short.class); 067 SUPPORTED_TYPES.add(int.class); 068 SUPPORTED_TYPES.add(long.class); 069 SUPPORTED_TYPES.add(float.class); 070 SUPPORTED_TYPES.add(double.class); 071 SUPPORTED_TYPES.add(Boolean.class); 072 SUPPORTED_TYPES.add(Character.class); 073 SUPPORTED_TYPES.add(Byte.class); 074 SUPPORTED_TYPES.add(Short.class); 075 SUPPORTED_TYPES.add(Integer.class); 076 SUPPORTED_TYPES.add(Long.class); 077 SUPPORTED_TYPES.add(Float.class); 078 SUPPORTED_TYPES.add(Double.class); 079 SUPPORTED_TYPES.add(Void.class); 080 SUPPORTED_TYPES.add(Date.class); 081 SUPPORTED_TYPES.add(Calendar.class); 082 SUPPORTED_TYPES.add(LocalDate.class); 083 SUPPORTED_TYPES.add(LocalDateTime.class); 084 SUPPORTED_TYPES.add(LocalTime.class); 085 SUPPORTED_TYPES.add(Duration.class); 086 SUPPORTED_TYPES.add(Instant.class); 087 } 088 089 public SapJcoProducer(SapJcoEndpoint endpoint) 090 { 091 super(endpoint); 092 this.endpoint = endpoint; 093 } 094 095 public void process(Exchange exchange) throws Exception 096 { 097 JCoDestination destination = JCoDestinationManager.getDestination(endpoint.getSapDestName()); 098 JCoFunction function = destination.getRepository().getFunction(endpoint.getSapFunction()); 099 setParams(exchange, function); 100 function.execute(destination); 101 102 JCoTable codes = function.getTableParameterList().getTable(endpoint.getSapJcoTable()); 103 List<Object> result = new ArrayList<Object>(); 104 ParserResult<?> parserResult = getParserResult(); 105 for (int i = 0; i < codes.getNumRows(); i++) 106 { 107 codes.setRow(i); 108 Object o = parserResult.getValues(codes, i); 109 if (o != null || endpoint.isSupportsNull()) 110 result.add(o); 111 } 112 // preserve headers 113 exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders()); 114 exchange.getOut().setBody(result); 115 } 116 117 @SuppressWarnings("unchecked") 118 private <T> ParserResult<T> getParserResult() 119 { 120 ParserResult<T> result = null; 121 try 122 { 123 result = (ParserResult<T>) endpoint.getClassToParserResultStrategy().newInstance(); 124 } 125 catch (InstantiationException | IllegalAccessException e) 126 { 127 throw new RuntimeCamelException( 128 "Cannot create new instance of [" + endpoint.getParserResultStrategy() + "]", e); 129 } 130 return result; 131 } 132 133 @SuppressWarnings("unchecked") 134 private void setParams(Exchange exchange, JCoFunction function) 135 { 136 Map<String, Object> params = getParams(exchange); 137 Set<String> keys = params.keySet(); 138 //Find structure parameter with this name and set the appropriate values 139 JCoFieldIterator iter = function.getImportParameterList().getFieldIterator(); 140 while (iter.hasNextField()) 141 { 142 JCoField f = iter.nextField(); 143 //LOG.debug("field={}, isTable={}, isStructure={}", f.getName(), f.isTable(), f.isStructure()); 144 if (f.isStructure()) 145 { 146 setStructureParameter(f, params); 147 } 148 else 149 { 150 Object value = params.get(f.getName()); 151 if (isSupportedType(value)) 152 { 153 function.getImportParameterList().setValue(f.getName(), value); 154 if (LOG.isDebugEnabled()) 155 LOG.debug("setting param=[{}] value=[{}], typeof=[{}], prefix=[{}]", f.getName(), value, 156 (value != null ? value.getClass().getName() : "null"), endpoint.getPrefixParams()); 157 } 158 else 159 LOG.info("Type [{}] not is supported as parameter try a type of {}", value.getClass(), 160 SUPPORTED_TYPES); 161 } 162 } 163 if (endpoint.getSapJcoTableIn() != null && !endpoint.getSapJcoTableIn().equals("")) 164 { 165 JCoTable codes = function.getTableParameterList().getTable(endpoint.getSapJcoTableIn()); 166 if (codes != null) 167 { 168 //LOG.debug("{}", codes); 169 Object tableIn = getParams(exchange).get(endpoint.getSapJcoTableIn()); 170 if (tableIn instanceof List) 171 { 172 List<Map<String, Object>> list = (List<Map<String, Object>>) tableIn; 173 setTableParameter(codes, list); 174 } 175 else if (tableIn != null) 176 { 177 LOG.warn("The parameter sapJcoTableIn must be instance of List of Map, type [{}] isn't supported", 178 tableIn.getClass()); 179 } 180 } 181 } 182 } 183 184 /** 185 * Sets a single Importing or Changing parameter that is a structure 186 * @param f field name of parameter 187 * @param map the value of the parameter 188 */ 189 private void setStructureParameter(JCoField f, Map<String, Object> map) 190 { 191 Iterator fieldIter = map.entrySet().iterator(); 192 JCoStructure structure = f.getStructure(); 193 while (fieldIter.hasNext()) 194 { 195 Entry field = (Map.Entry) fieldIter.next(); 196 String k = field.getKey().toString(); 197 Object v = field.getValue(); 198 if (isSupportedType(v)) 199 { 200 structure.setValue(k, v); 201 if (LOG.isDebugEnabled()) 202 LOG.debug("setting param=[{}] value=[{}], typeof=[{}], prefix=[{}]", k, v, 203 (v != null ? v.getClass().getName() : "null"), endpoint.getPrefixParams()); 204 } 205 } 206 } 207 208 /** 209 * Sets a single Table parameter that is a structure 210 * @param table JCo table for input parameters 211 * @param list The value of the parameter (A List of HashMap) 212 */ 213 @SuppressWarnings("unchecked") 214 private void setTableParameter(JCoTable table, List<Map<String, Object>> list) 215 { 216 Iterator it = list.listIterator(); 217 while (it.hasNext()) 218 { 219 table.appendRow(); 220 Map<String, Object> params = (Map<String, Object>) it.next(); 221 Iterator itParams = params.entrySet().iterator(); 222 while (itParams.hasNext()) 223 { 224 Entry<String, Object> entry = (Map.Entry<String, Object>) itParams.next(); 225 table.setValue(entry.getKey(), entry.getValue()); 226 if (LOG.isDebugEnabled()) 227 LOG.debug("setting param=[{}] value=[{}], typeof=[{}]", entry.getKey(), entry.getValue(), 228 (entry.getValue() != null ? entry.getValue().getClass().getName() : "null")); 229 230 } 231 } 232 } 233 234 /* 235 public void setStructureParameter(JCoFunction function, String name, Map<String, Object> map) 236 { 237 //Find structure parameter with this name and set the appropriate values 238 JCoFieldIterator iter = function.getImportParameterList().getFieldIterator(); 239 while(iter.hasNextField()) 240 { 241 JCoField f = iter.nextField(); 242 if(f.getName().equals(name) & f.isStructure()) 243 { 244 Iterator fieldIter = map.entrySet().iterator(); 245 JCoStructure structure = f.getStructure(); 246 while(fieldIter.hasNext()) 247 { 248 Entry field = (Map.Entry)fieldIter.next(); 249 structure.setValue(field.getKey().toString(), field.getValue().toString()); 250 LOG.debug("setting param=[{}] value=[{}], typeof=[{}], prefix=[{}]", field.getKey().toString(), field.getValue().toString(), 251 field.getValue().getClass().getName(), endpoint.getPrefixParams() ); 252 } 253 } 254 } 255 } 256 */ 257 258 /* 259 * Sets a single Table parameter that is a structure 260 * @param name the name of the parameter 261 * @param list The value of the parameter (A LinkedList of LinkedHashmaps) 262 * 263 private void setTableParameter(JCoFunction function, String name, LinkedList list) 264 { 265 //Find table parameter with this name and set the appropriate valies 266 JCoFieldIterator iter = function.getTableParameterList().getFieldIterator(); 267 while(iter.hasNextField()) 268 { 269 JCoField f = iter.nextField(); 270 if(f.getName().equals(name) & f.isTable() ) 271 { 272 Iterator recordIter = list.listIterator(); 273 JCoTable table = f.getTable(); 274 while(recordIter.hasNext()) 275 { 276 table.appendRow(); 277 LinkedHashMap fields = (LinkedHashMap)recordIter.next(); 278 Iterator fieldIter = fields.entrySet().iterator(); 279 while(fieldIter.hasNext()) 280 { 281 Entry field = (Map.Entry)fieldIter.next(); 282 table.setValue(field.getKey().toString(), field.getValue().toString()); 283 } 284 } 285 } 286 } 287 } 288 */ 289 290 @SuppressWarnings("unchecked") 291 private Map<String, Object> getParams(Exchange exchange) 292 { 293 Map<String, Object> params = exchange.getIn().getBody(Map.class); 294 boolean usingPrefix = false; 295 if (endpoint.isUseHeaderAsParam() || params == null || params.isEmpty()) 296 { 297 Map<String, Object> paramsSap = exchange.getIn().getHeader(endpoint.getPrefixParams(), Map.class); 298 if (paramsSap == null) 299 paramsSap = exchange.getIn().getHeaders(); 300 301 Set<String> keys = paramsSap.keySet(); 302 params = new HashMap<String, Object>(); 303 for (String key : keys) 304 { 305 if (key.startsWith(endpoint.getPrefixParams())) 306 { 307 usingPrefix = true; 308 String paramName = key.substring(endpoint.getPrefixParams().length()); 309 Object value = paramsSap.get(key); 310 params.put(paramName, value); 311 } 312 } 313 } 314 if (endpoint.isUseHeaderAsParam() && !usingPrefix) 315 { 316 LOG.warn("When Endpoint option useHeaderAsParam=true the parameters name must be prefixed with [{}]", 317 endpoint.getPrefixParams()); 318 } 319 return params; 320 } 321 322 private boolean isSupportedType(Object value) 323 { 324 boolean supported = true; 325 if (value != null) 326 { 327 supported = SUPPORTED_TYPES.contains(value.getClass()); 328 } 329 return supported; 330 } 331}