/******************************************************************************* * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * *******************************************************************************/ package com.liferay.ide.portal.core.debug.fm; import freemarker.debug.DebugModel; import freemarker.template.TemplateModelException; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IValue; import org.eclipse.debug.core.model.IVariable; /** * @author Gregory Amerson */ public class FMValue extends FMDebugElement implements IValue { private static final int VALID_VARIBLE_TYPES = DebugModel.TYPE_BOOLEAN | DebugModel.TYPE_COLLECTION | DebugModel.TYPE_CONFIGURATION | DebugModel.TYPE_DATE | DebugModel.TYPE_HASH | DebugModel.TYPE_HASH_EX | DebugModel.TYPE_NUMBER | DebugModel.TYPE_SCALAR | DebugModel.TYPE_SEQUENCE | DebugModel.TYPE_TEMPLATE; protected DebugModel debugModel; protected FMStackFrame stackFrame; private IVariable[] variables; public FMValue( FMStackFrame stackFrame, DebugModel debugModel ) { super( stackFrame.getDebugTarget() ); this.stackFrame = stackFrame; this.debugModel = debugModel; } public String getValueString() throws DebugException { String retval = null; try { int types = this.debugModel.getModelTypes(); if( ( DebugModel.TYPE_BOOLEAN & types ) > 0 ) { retval = Boolean.toString( this.debugModel.getAsBoolean() ); } if( ( DebugModel.TYPE_COLLECTION & types ) > 0 ) { retval = "Collection"; } if( ( DebugModel.TYPE_CONFIGURATION & types ) > 0 ) { retval = "Configuration"; } if( ( DebugModel.TYPE_DATE & types ) > 0 ) { retval = this.debugModel.getAsDate().toString(); } if( ( DebugModel.TYPE_ENVIRONMENT & types ) > 0 ) { retval = "Environment"; } if( ( DebugModel.TYPE_HASH & types ) > 0 ) { retval = "Hash"; } if( ( DebugModel.TYPE_HASH_EX & types ) > 0 ) { retval = "HashEx"; } if( ( DebugModel.TYPE_NUMBER & types ) > 0 ) { retval = this.debugModel.getAsNumber().toString(); } if( ( DebugModel.TYPE_SCALAR & types ) > 0 ) { retval = this.debugModel.getAsString(); } if( ( DebugModel.TYPE_SEQUENCE & types ) > 0 ) { retval = "Sequence"; } if( ( DebugModel.TYPE_TEMPLATE & types ) > 0 ) { retval = "Template"; } if( ( DebugModel.TYPE_TRANSFORM & types ) > 0 ) { retval = "Transform"; } } catch( Exception e ) { e.printStackTrace(); } if( retval == null ) { retval = ""; } return retval; } private String getCollectionDetailString( DebugModel model ) { StringBuilder sb = new StringBuilder(); sb.append( '[' ); try { for( int i = 0; i < model.size(); i++ ) { final DebugModel val = model.get( i ); final String value = getModelDetailString( val ); if( value != null ) { sb.append( value ); sb.append(','); } } } catch( Exception e ) { sb.append( e.getMessage() ); } String value = sb.toString(); return value.endsWith( "," ) ? value.replaceFirst( ",$", "]" ) : value; } private String getSequenceDetailString( DebugModel model ) { StringBuilder sb = new StringBuilder(); sb.append( '[' ); try { for( int i = 0; i < model.size(); i++ ) { final DebugModel val = model.get( i ); final String value = getModelDetailString( val ); if( value != null ) { sb.append( value ); sb.append(','); } } } catch( Exception e ) { sb.append( e.getMessage() ); } String value = sb.toString(); return value.endsWith( "," ) ? value.replaceFirst( ",$", "]" ) : value; } private String getModelDetailString( DebugModel model ) throws RemoteException, TemplateModelException { String value = null; final int modelTypes = model.getModelTypes(); if( isStringType( modelTypes ) && !isHashType( modelTypes ) ) { value = model.getAsString(); } else if( isNumberType( modelTypes ) ) { value = model.getAsNumber().toString(); } else if( isDateType( modelTypes ) ) { value = model.getAsDate().toString(); } else if( isBooleanType( modelTypes ) ) { value = Boolean.toString( model.getAsBoolean() ); } else if( isHashType( modelTypes ) ) { // value = getHashDetailString( model ); value = "Hash"; } else if( isCollectionType( modelTypes ) ) { // value = getHashDetailString( model ); value = "Collection"; } else if( isSequenceType( modelTypes ) ) { // value = getSequenceDetailString( model ); value = "Sequence"; } else if( isMethodType( modelTypes) || isTransformType( modelTypes ) || modelTypes == 0 ) { value = null; } else { System.out.println("unsupported detail model type: " + modelTypes ); } return value; } public String getDetailString() { String retval = null; try { int types = this.debugModel.getModelTypes(); if( ( DebugModel.TYPE_BOOLEAN & types ) > 0 ) { retval = Boolean.toString( this.debugModel.getAsBoolean() ); } if( ( DebugModel.TYPE_COLLECTION & types ) > 0 ) { retval = getCollectionDetailString( this.debugModel ); } if( ( DebugModel.TYPE_CONFIGURATION & types ) > 0 ) { retval = "Configuration"; } if( ( DebugModel.TYPE_DATE & types ) > 0 ) { retval = this.debugModel.getAsDate().toString(); } if( ( DebugModel.TYPE_ENVIRONMENT & types ) > 0 ) { retval = "Environment"; } if( ( DebugModel.TYPE_HASH & types ) > 0 ) { retval = "Hash"; } if( ( DebugModel.TYPE_HASH_EX & types ) > 0 ) { retval = getHashDetailString( this.debugModel ); } if( ( DebugModel.TYPE_NUMBER & types ) > 0 ) { retval = this.debugModel.getAsNumber().toString(); } if( ( DebugModel.TYPE_SCALAR & types ) > 0 ) { retval = this.debugModel.getAsString(); } if( ( DebugModel.TYPE_SEQUENCE & types ) > 0 ) { retval = getSequenceDetailString( this.debugModel ); } if( ( DebugModel.TYPE_TEMPLATE & types ) > 0 ) { retval = "Template"; } if( ( DebugModel.TYPE_TRANSFORM & types ) > 0 ) { retval = "Transform"; } } catch( Exception e ) { e.printStackTrace(); } if( retval == null ) { retval = ""; } return retval; } private String getHashDetailString( DebugModel model ) { StringBuilder sb = new StringBuilder(); sb.append( '{' ); try { for( String key : model.keys() ) { final DebugModel val = model.get( key ); final String value = getModelDetailString( val ); if( value != null ) { sb.append( key ); sb.append('='); sb.append( value ); sb.append(','); } } } catch( Exception e ) { sb.append( e.getMessage() ); } String value = sb.toString(); return value.endsWith( "," ) ? value.replaceFirst( ",$", "}" ) : value; } public boolean isAllocated() throws DebugException { return true; } public IVariable[] getVariables() throws DebugException { /* * Represents the debugger-side mirror of a debugged freemarker.core.Environment object in the remote VM. * * This interface extends DebugModel, and the properties of the Environment are exposed as hash keys on it. * Specifically, the following keys are supported: "currentNamespace", "dataModel", "globalNamespace", * "knownVariables", "mainNamespace", and "template". * * The debug model for the template supports keys * "configuration" and "name". * * The debug model for the configuration supports key "sharedVariables". * Additionally, all of the debug models for environment, template, and configuration also support all the * setting keys of freemarker.core.Configurable objects. */ if( this.variables == null ) { List<IVariable> vars = new ArrayList<IVariable>(); try { int types = this.debugModel.getModelTypes(); if( isHashType( types) ) { try { String[] keys = this.debugModel.keys(); DebugModel[] vals = this.debugModel.get( keys ); for( int i = 0; i < keys.length; i++ ) { DebugModel hashValue = vals[i]; if( isValidVariable( hashValue ) ) { vars.add( new FMVariable( stackFrame, keys[i] , hashValue ) ); } } } catch( ClassCastException cce ) { // ignore IDE-1082 } } else if( isCollectionType( types ) ) { // String[] keys = this.debugModel.keys(); // if( isValidVariable( hashValue ) ) // { // vars.add( new FMVariable( stackFrame, key , debugModel ) ); // } } else if( isSequenceType( types ) && isValidSequence( this.debugModel ) ) { int length = this.debugModel.size(); DebugModel[] vals = this.debugModel.get( 0, length ); for( int i = 0; i < length; i++ ) { if( isValidVariable( vals[i] ) ) { vars.add( new FMVariable( stackFrame, Integer.toString( i ), vals[i] ) ); } } } else if( isStringType( types ) || isNumberType( types ) || isBooleanType( types ) || isDateType( types ) ) { // no variables } else { System.out.println( "Unknown value: " + getReferenceTypeName( this.debugModel ) ); } } catch( Exception e ) { e.printStackTrace(); } this.variables = vars.toArray( new IVariable[vars.size()] ); sortVariables( this.variables ); } return this.variables; } private boolean isValidSequence( DebugModel model ) { try { return model != null && model.size() > 0; } catch( Exception e ) { return false; } } private boolean isHashType( int types ) { return ( DebugModel.TYPE_HASH & types ) > 0 || ( DebugModel.TYPE_HASH_EX & types ) > 0; } private boolean isMethodType( int types ) { return ( DebugModel.TYPE_METHOD & types ) > 0 || ( DebugModel.TYPE_METHOD_EX & types ) > 0; } private boolean isTransformType( int types ) { return ( DebugModel.TYPE_TRANSFORM & types ) > 0; } private boolean isStringType( int types ) { return ( DebugModel.TYPE_SCALAR & types ) > 0; } private boolean isNumberType( int types ) { return ( DebugModel.TYPE_NUMBER & types ) > 0; } private boolean isDateType( int types ) { return ( DebugModel.TYPE_DATE & types ) > 0; } private boolean isBooleanType( int types ) { return ( DebugModel.TYPE_BOOLEAN & types ) > 0; } private boolean isCollectionType( int types ) { return ( DebugModel.TYPE_COLLECTION & types ) > 0; } private boolean isSequenceType( int types ) { return ( DebugModel.TYPE_SEQUENCE & types ) > 0; } private boolean isValidVariable( DebugModel model ) { boolean retval = false; if( model != null ) { try { int types = model.getModelTypes(); retval = ( VALID_VARIBLE_TYPES & types ) > 0; if( retval && isSequenceType( types ) && ! isValidSequence( model ) ) { retval = false; } } catch( RemoteException e ) { e.printStackTrace(); } } return retval; } public boolean hasVariables() throws DebugException { try{ return getVariables().length > 0; } catch (NullPointerException e) { return false; } } public String getReferenceTypeName() throws DebugException { return getReferenceTypeName( this.debugModel ); } }