Skip to content
Ralph Schaer edited this page Jul 10, 2012 · 21 revisions

How to configure ExtDirectSpring

With the class ch.ralscha.extdirectspring.controller.Configuration it is possible to tweak different aspects of ExtDirectSpring.

RemotingProvider Configuration

The three properties timeout, maxRetries and enableBuffer configure a RemotingProvider. Description about these properties.

     <bean id="extDirectSpringConfiguration" 
      class="ch.ralscha.extdirectspring.controller.Configuration" 
      p:timeout="12000" p:maxRetries="10" p:enableBuffer="false"/>

A call to api.js is sending these parameters if specified to the client as part of the remoting configuration.

Example output of a call to api-debug.js with the above configuration present in the Spring context. Ext.ns('Ext.app');

Ext.app.REMOTING_API = {
  "url" : "/controller/router",
  "type" : "remoting",
  "actions" : {
    "treeProvider" : [ {
      "name" : "getTree",
      "len" : 1
    } ]
  },
  "timeout" : 12000,
  "maxRetries" : 10,
  "enableBuffer" : false
};

If not specified the server does not send these three properties to the client. RemotingProvider will then use these default values: timeout=30000, maxRetries=1 and enableBuffer=10


synchronizeOnSession

Defaults to false. Setting this property to true will wrap every call to a @ExtDirectMethod in a synchronized statements. This is useful when the server method needs to manipulate session objects. <bean id="extDirectSpringConfiguration" class="ch.ralscha.extdirectspring.controller.Configuration" p:synchronizeOnSession="true"

Instead of globally turn on this feature every method can individually specify the synchronizeOnSession with the @ExtDirectMethod annotation.

@ExtDirectMethod(value = ExtDirectMethodType.STORE_MODIFY, synchronizeOnSession=true)
public List<User> create(List<User> newUsers) {
  //...
}

FORM_POST method do not support this feature.


streamResponse (since 1.1.0)

This property specifies that the Jackson ObjectMapper should work like in version 1.0.x and write the response directly into the http servlet response without setting the http header Content-Length (true). If set to false (default) the ObjectMapper first writes the response into an internal buffer, sets the Content-Length header and then writes the response into the http servlet response.

Instead of globally turn on this feature every method can individually configure the streamResponse property with the @ExtDirectMethod annotation.


Error Messages

If an exception happens on the server and there is no special configuration present the server sends this response back to the client. message contains the text "Server Error" and type the text "exception". [ { "method": "method4", "action": "remoteProviderSimple", "tid": 2, "message": "Server Error", "type": "exception" } ]

To tweak this behavior add a bean with id extDirectSpringConfiguration and type ch.ralscha.extdirectspring.controller.Configuration to the Spring context.

<context:component-scan base-package="ch.ralscha.extdirectspring" />
<mvc:annotation-driven />

<bean id="extDirectSpringConfiguration" 
      class="ch.ralscha.extdirectspring.controller.Configuration" 
      p:defaultExceptionMessage="Panic!!!"
      p:sendExceptionMessage="false"
      p:sendStacktrace="true">
  <property name="exceptionToMessage">
    <map>
      <entry key="java.lang.IllegalArgumentException" 
             value="illegal argument"/>
      <entry key="org.springframework.beans.factory.NoSuchBeanDefinitionException">
        <null/>
      </entry>
    </map>
  </property>

</bean>
defaultExceptionMessage Defines the default exception message. Field *message* in the response Default: 'Server Error'
sendExceptionMessage If true sends exception.getMessage() back. Field *message* in the response Default: false
sendStacktrace If true sends the whole stacktrace in the field *where* back Default: false
exceptionToMessage Mapping from exception class (key) to message (value) Default: empty

Rules for response field message:

  1. If there is a mapping for the exception in exceptionToMessage and the value is not null send this value.
  2. If there is a mapping for the exception in exceptionToMessage and the value is null send exception.getMessage().
  3. If there is no mapping and sendExceptionMessage is true send exception.getMessage().
  4. If there is no mapping and sendExceptionMessage is false send defaultExceptionMessage.

Special Exception Handling for FORM_POST methods
Because FORM_POST are handled differently by ExtDirectSpring they are not covered by this Exception processing. It is therefore necessary to add a special exception handling. One solution is writing a HandlerExceptionResolver to handle exception from these methods. @Component @Lazy public class ExceptionHandler implements HandlerExceptionResolver, InitializingBean { private final static Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

  private ObjectMapper mapper = new ObjectMapper();

  @Autowired(required = false)
  private Configuration configuration;

  @Override
  public void afterPropertiesSet() throws Exception {
    if (configuration == null) {
      configuration = new Configuration();
    }
  }

  @Override
  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse res, Object handler,
      Exception ex) {

    ExtDirectResponseBuilder builder = new ExtDirectResponseBuilder(request);
    builder.unsuccessful();

    ExtDirectResponse response = builder.build();
    response.setType("exception");
    response.setMessage(configuration.getMessage(ex));

    if (configuration.isSendStacktrace()) {
      response.setWhere(getStackTrace(ex));
    } else {
      response.setWhere(null);
    }

    try {
      res.getOutputStream().print(mapper.writeValueAsString(response));
      res.getOutputStream().flush();
    } catch (IOException e) {
      //...
    }

    return null;
  }

  private String getStackTrace(final Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
  }
}
Clone this wiki locally