/* * Copyright 2013 Nokia Solutions and Networks Oyj * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.robotframework.javalib.library; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import org.robotframework.javalib.annotation.Autowired; import org.robotframework.javalib.beans.annotation.AnnotationBasedKeywordFilter; import org.robotframework.javalib.beans.annotation.IBeanLoader; import org.robotframework.javalib.beans.annotation.KeywordBeanLoader; import org.robotframework.javalib.beans.common.IClassFilter; import org.robotframework.javalib.factory.AnnotationKeywordFactory; import org.robotframework.javalib.factory.KeywordFactory; import org.robotframework.javalib.keyword.DocumentedKeyword; public class AnnotationLibrary extends KeywordFactoryBasedLibrary<DocumentedKeyword> implements KeywordDocumentationRepository { protected List<IBeanLoader> beanLoaders = new ArrayList<IBeanLoader>(); protected IClassFilter classFilter = new AnnotationBasedKeywordFilter(); private KeywordFactory<DocumentedKeyword> keywordFactory; public AnnotationLibrary() { } public AnnotationLibrary(String keywordPattern) { addKeywordPattern(keywordPattern); } public AnnotationLibrary(List<String> keywordPatterns) { for (String pattern : keywordPatterns) { addKeywordPattern(pattern); } } @Override protected KeywordFactory<DocumentedKeyword> createKeywordFactory() { assumeKeywordPatternIsSet(); if (keywordFactory == null) { List<Map> keywordBeansMaps = new ArrayList<Map>(); for (IBeanLoader beanLoader : beanLoaders) { keywordBeansMaps.add(beanLoader.loadBeanDefinitions(classFilter)); } keywordFactory = new AnnotationKeywordFactory(keywordBeansMaps); List<Object> injectionValues = new ArrayList<Object>(); injectionValues.add(this); for (Map keywordBeansMap : keywordBeansMaps) { injectionValues.addAll(keywordBeansMap.values()); } for (Object injectionTarget : injectionValues) { autowireFields(injectionTarget, injectionValues); } } return keywordFactory; } protected void autowireFields(Object injectionTarget, Collection<Object> injectionValues) { Class<?> objectClass = injectionTarget.getClass(); while (objectClass != null) { Field[] fields = objectClass.getDeclaredFields(); next_field: for (final Field field : fields) { try { if (field.isAnnotationPresent(Autowired.class)) { if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass() .getModifiers())) && !field.isAccessible()) { field.setAccessible(true); } Class<?> fieldClass = field.getType(); for (Object injectionValue : injectionValues) { if (injectionValue.getClass().equals(fieldClass)) { field.set(injectionTarget, injectionValue); continue next_field; } } throw new IllegalArgumentException(String.format( "Can't autowire field '%s' at keyword class '%s'.", field.getName(), injectionTarget .getClass().getName())); } } catch (IllegalAccessException e) { throw new IllegalArgumentException(String.format( "Can't autowire field '%s' at keyword class '%s'.", field.getName(), injectionTarget .getClass().getName()), e); } } objectClass = objectClass.getSuperclass(); } } public String[] getKeywordArguments(String keywordName) { return createKeywordFactory().createKeyword(keywordName).getArgumentNames(); } /** * This method should be overridden in the Library implementation including * the equals comparison for '__intro__'. * * Default implementation returns empty String for the '__intro__'. */ public String getKeywordDocumentation(String keywordName) { if (keywordName.equals("__intro__")) return ""; return createKeywordFactory().createKeyword(keywordName).getDocumentation(); } @Override public Object runKeyword(String keywordName, Object[] args) { try { return super.runKeyword(keywordName, args); } catch (RuntimeException e) { throw retrieveInnerException(e); } } public void addKeywordPattern(String keywordPattern) { beanLoaders.add(new KeywordBeanLoader(keywordPattern, Thread.currentThread().getContextClassLoader())); } private void assumeKeywordPatternIsSet() { if (beanLoaders.isEmpty()) { throw new IllegalStateException("Keyword pattern must be set before calling getKeywordNames."); } } private RuntimeException retrieveInnerException(RuntimeException e) { Throwable cause = e.getCause(); if (cause != null && InvocationTargetException.class.equals(cause.getClass())) { Throwable original = cause.getCause(); return new RuntimeException(original.getMessage(), original); } return e; } }