/* * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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.kie.workbench.common.services.datamodeller.driver.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.regex.Pattern; import org.jboss.forge.roaster.model.ValuePair; import org.jboss.forge.roaster.model.source.AnnotationSource; import org.kie.workbench.common.services.datamodeller.core.Annotation; import org.kie.workbench.common.services.datamodeller.core.AnnotationDefinition; import org.kie.workbench.common.services.datamodeller.core.AnnotationValuePairDefinition; import org.kie.workbench.common.services.datamodeller.core.impl.AnnotationImpl; import org.kie.workbench.common.services.datamodeller.driver.AnnotationDriver; import org.kie.workbench.common.services.datamodeller.driver.ModelDriverException; import org.kie.workbench.common.services.datamodeller.util.DriverUtils; import org.kie.workbench.common.services.datamodeller.util.NamingUtils; import org.kie.workbench.common.services.datamodeller.util.PortableStringUtils; import org.kie.workbench.common.services.datamodeller.util.StringEscapeUtils; public class DefaultJavaRoasterModelAnnotationDriver implements AnnotationDriver { @Override public Annotation buildAnnotation( AnnotationDefinition annotationDefinition, Object annotationToken ) throws ModelDriverException { AnnotationSource javaAnnotationToken = ( AnnotationSource ) annotationToken; AnnotationImpl annotation = new AnnotationImpl( annotationDefinition ); if ( annotationDefinition.isMarker() ) { return annotation; } else { if ( javaAnnotationToken.getValues() != null ) { List<ValuePair> values = javaAnnotationToken.getValues(); if ( values != null && values.size() > 0 ) { for ( AnnotationValuePairDefinition valuePairDefinition : annotationDefinition.getValuePairs() ) { Object annotationValue = buildAnnotationValue( javaAnnotationToken, valuePairDefinition ); if ( annotationValue != null ) { annotation.setValue( valuePairDefinition.getName(), annotationValue ); } } } } } return annotation; } private Object buildAnnotationValue( AnnotationSource javaAnnotationToken, AnnotationValuePairDefinition valuePairDefinition ) throws ModelDriverException { Object result = null; if ( javaAnnotationToken.getLiteralValue( valuePairDefinition.getName() ) != null ) { //there's a value if ( valuePairDefinition.isPrimitiveType() ) { result = parsePrimitiveValue( javaAnnotationToken, valuePairDefinition ); } else if ( valuePairDefinition.isEnum() ) { result = parseEnumValue( javaAnnotationToken, valuePairDefinition ); } else if ( valuePairDefinition.isString() ) { result = parseStringValue( javaAnnotationToken, valuePairDefinition ); } else if ( valuePairDefinition.isClass() ) { result = parseClassValue( javaAnnotationToken, valuePairDefinition ); } else if ( valuePairDefinition.isAnnotation() ) { result = parseAnnotationValue( javaAnnotationToken, valuePairDefinition ); } } return result; } private Object parsePrimitiveValue( AnnotationSource javaAnnotationToken, AnnotationValuePairDefinition valuePairDefinition ) { String value = parseLiteralValue( javaAnnotationToken.getLiteralValue( valuePairDefinition.getName() ) ); Object result; if ( value == null ) { return null; } if ( valuePairDefinition.isArray() ) { result = parsePrimitiveArrayValue( value, valuePairDefinition.getClassName(), valuePairDefinition ); } else { result = parsePrimitiveValue( value, valuePairDefinition.getClassName() ); } return result; } private Object parseEnumValue( AnnotationSource javaAnnotationToken, AnnotationValuePairDefinition valuePairDefinition ) { String value = parseLiteralValue( javaAnnotationToken.getLiteralValue( valuePairDefinition.getName() ) ); Object result; if ( value == null ) { return null; } if ( valuePairDefinition.isArray() ) { result = parseEnumArrayValue( value, valuePairDefinition ); } else { result = parseEnumValue( value, valuePairDefinition ); } return result; } private Object parseStringValue( AnnotationSource javaAnnotationToken, AnnotationValuePairDefinition valuePairDefinition ) { Object result = null; if ( valuePairDefinition.isArray() ) { String[] arrayValue = javaAnnotationToken.getStringArrayValue( valuePairDefinition.getName() ); if ( arrayValue != null ) { result = Arrays.asList( arrayValue ); } } else { result = javaAnnotationToken.getStringValue( valuePairDefinition.getName() ); } return result; } private Object parseClassValue( AnnotationSource javaAnnotationToken, AnnotationValuePairDefinition valuePairDefinition ) { String value = null; Object result; List<ValuePair> values = javaAnnotationToken.getValues(); if ( values != null ) { Optional<ValuePair> valuePair = values.stream().filter( vp -> valuePairDefinition.getName().equals( vp.getName() ) ).findFirst( ); value = valuePair.map( vp -> vp.getLiteralValue() ).orElse( null ); } if ( value == null ) { return null; } if ( valuePairDefinition.isArray() ) { result = parseClassArrayValue( value ); } else { result = value; } return result; } private Object parseAnnotationValue( AnnotationSource javaAnnotationToken, AnnotationValuePairDefinition valuePairDefinition ) throws ModelDriverException { String value = javaAnnotationToken.getLiteralValue( valuePairDefinition.getName() ); AnnotationDefinition annotationDefinition = valuePairDefinition.getAnnotationDefinition(); Object result = null; if ( value == null ) return null; if ( annotationDefinition == null ) { return value; } if ( valuePairDefinition.isArray() ) { AnnotationSource[] javaAnnotationTokenValueArray = javaAnnotationToken.getAnnotationArrayValue( valuePairDefinition.getName() ); List<Annotation> annotationList = new ArrayList<Annotation>(); Annotation annotation; if ( javaAnnotationTokenValueArray != null ) { for ( int i = 0; i < javaAnnotationTokenValueArray.length; i++ ) { annotation = buildAnnotation( annotationDefinition, javaAnnotationTokenValueArray[ i ] ); if ( annotation != null ) { annotationList.add( annotation ); } } } result = annotationList.size() > 0 ? annotationList : null; } else { AnnotationSource javaAnnotationTokenValue = javaAnnotationToken.getAnnotationValue( valuePairDefinition.getName() ); if ( javaAnnotationTokenValue != null ) { result = buildAnnotation( annotationDefinition, javaAnnotationTokenValue ); } } return result; } private Object parsePrimitiveValue( String value, String className ) { if ( NamingUtils.isByteId( className ) ) { return parseByteValue( value, className ); } else if ( NamingUtils.isCharId( className ) ) { return parseCharValue( value, className ); } else { return NamingUtils.parsePrimitiveValue( className, value ); } } private List<Object> parsePrimitiveArrayValue( String value, String className, AnnotationValuePairDefinition valuePairDefinition ) { if ( value == null ) return null; List<Object> values = new ArrayList<Object>( ); value = value.trim(); if ( !value.startsWith( "{" ) || !value.endsWith( "}" ) ) { //mal formed array return values; } else if ( DriverUtils.isEmptyArray( value ) ) { return values; } else { value = PortableStringUtils.removeLastChar( PortableStringUtils.removeFirstChar( value, '{' ), '}' ); String[] primitiveValues = value.split( "," ); Object primitiveValue; for ( int i = 0; i < primitiveValues.length; i++ ) { primitiveValue = parsePrimitiveValue( primitiveValues[i], className ); values.add( primitiveValue ); } } return values; } private Object parseByteValue( String value, String className ) { //remove the word (byte) in case the value is something like (byte)222" String regex = "(\\s)*\\((\\s)*byte(\\s)*\\)(\\s)*"; Pattern pattern = Pattern.compile( regex ); String[] splits = pattern.split( value ); Object result = null; try { if ( splits.length == 0 ) { result = NamingUtils.parsePrimitiveValue( className, value ); } else if ( splits.length == 1 ) { result = NamingUtils.parsePrimitiveValue( className, splits[ 0 ] ); } else if ( splits.length == 2 ) { result = NamingUtils.parsePrimitiveValue( className, splits[ 1 ] ); } else { result = NamingUtils.parsePrimitiveValue( className, value ); } } catch ( NumberFormatException e ) { result = value; } return result; } private Object parseCharValue( String value, String className ) { String unquotedValue = StringEscapeUtils.unquoteSingle( value ); return NamingUtils.parsePrimitiveValue( className, unquotedValue ); } private Object parseEnumValue( String value, AnnotationValuePairDefinition valuePairDefinition ) { String[] enumValues = valuePairDefinition.enumValues(); String result = value; if ( value != null && enumValues != null ) { for ( int i = 0; i < enumValues.length; i++ ) { if ( value.endsWith( enumValues[ i ] ) ) { result = enumValues[ i ]; break; } } } return result; } private List<Object> parseEnumArrayValue( String value, AnnotationValuePairDefinition valuePairDefinition ) { if ( value == null ) return null; List<Object> values = new ArrayList<Object>( ); value = value.trim(); if ( !value.startsWith( "{" ) || !value.endsWith( "}" ) ) { //mal formed array return values; } else if ( DriverUtils.isEmptyArray( value ) ) { return values; } else { value = PortableStringUtils.removeLastChar( PortableStringUtils.removeFirstChar( value, '{' ), '}' ); String[] enumValues = value.split( "," ); Object enumValue; for ( int i = 0; i < enumValues.length; i++ ) { enumValue = parseEnumValue( enumValues[i], valuePairDefinition ); values.add( enumValue ); } } return values; } private List<Object> parseClassArrayValue( String value ) { if ( value == null ) return null; List<Object> values = new ArrayList<Object>( ); value = value.trim(); if ( !value.startsWith( "{" ) || !value.endsWith( "}" ) ) { //mal formed array return values; } else if ( DriverUtils.isEmptyArray( value ) ) { return values; } else { value = PortableStringUtils.removeLastChar( PortableStringUtils.removeFirstChar( value, '{' ), '}' ); String[] classValues = value.split( "," ); Object classValue; for ( int i = 0; i < classValues.length; i++ ) { classValue = parseClassValue( classValues[i] ); if ( classValue != null ) { values.add( classValue ); } } } return values; } private String parseClassValue( String classValue ) { return classValue != null ? classValue.trim() : null; } private boolean isValidClassValue( String value ) { String classValue = value != null ? value.trim() : value; return classValue != null && classValue.length() > ".class".length() && classValue.endsWith( ".class" ); } private String parseLiteralValue( String literalValue ) { return literalValue; //literalValue != null ? StringEscapeUtils.unquote( StringEscapeUtils.unescapeJava( literalValue ) ) : literalValue; } }