I have a struts2 application which uses the struts2-rest-plugin v.2.2.3.
Everything is working great when it comes to the routing of the requests to the actions and its methods and I'm also using ModelDriven to specify the object to serialise when using extensions like JSON and XML.
The problem I'm having is that when I send a POST or PUT request to the struts layer I just get an empty response.
I am sending a POST request to the action like so: http://localhost:8080/alert-settings!update.json. I have a breakpoint in that method and it gets called and the code runs and completes. I have a feeling the issue might be that I am trying to use the ModelDriven interface to send me back the response and for some reason the rest-plugin doesn't like this but I don't know why it would behave like that.
Is there a known issue with receiving responses from POST requests while using the rest plugin? I have looked everywhere and can't find anything about it really.
Any help appreciated and I can provide any more details on request.
I encountered the same issue. Have you tried to set in the struts.xml file:
struts.rest.content.restrictToGET = false
See the last setting on the rest plugin docs
I actually figured out that it was a line in the rest plugin causing this:
// don't return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
target = null;
}
This is in org.apache.struts2.rest.RestActionInvocation in the selectTarget() method. I find this to be quite annoying as it doesn't really follow the REST architecture, id like the option to be able to return response objects for POST, DELETE and PUT requests in some cases.
I worked around this by extending RestActionProxyFactory and RestActionInvocation and specifying the use of this in my struts xml like so:
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />
This allows me to use the struts plugin throughout while returning object on POST requests.
RestActionProxyFactory
public class RPRestActionProxyFactory extends RestActionProxyFactory {
#Override
public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {
if (namespace.startsWith(this.namespace)) {
ActionInvocation inv = new RPRestActionInvocation(extraContext, true);
container.inject(inv);
return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
} else {
return super.createActionProxy(namespace, actionName, methodName, extraContext, executeResult, cleanupContext);
}
}
}
RestActionInvocation
public class RPRestActionInvocation extends RestActionInvocation {
public RPRestActionInvocation(Map extraContext, boolean pushAction) {
super(extraContext, pushAction);
}
#SuppressWarnings("unchecked")
#Override
protected void selectTarget() {
// Select target (content to return)
Throwable e = (Throwable)stack.findValue("exception");
if (e != null) {
// Exception
target = e;
hasErrors = true;
} else if (action instanceof ValidationAware && ((ValidationAware)action).hasErrors()) {
// Error messages
ValidationAware validationAwareAction = ((ValidationAware)action);
Map errors = new HashMap();
if (validationAwareAction.getActionErrors().size() > 0) {
errors.put("actionErrors", validationAwareAction.getActionErrors());
}
if (validationAwareAction.getFieldErrors().size() > 0) {
errors.put("fieldErrors", validationAwareAction.getFieldErrors());
}
target = errors;
hasErrors = true;
} else if (action instanceof ModelDriven) {
// Model
target = ((ModelDriven)action).getModel();
} else {
target = action;
}
// don't return any content for PUT, DELETE, and POST where there are no errors
// if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
// target = null;
// }
}
}
I've used struts actions with mixed result types in the past, returning json, xml, and tiles for instance. I'm not sure if it's the recommended way to do it but it requires some configuration using struts.xml even though conventions are being used. Maybe you've already done this, not sure there isn't enough info provided to tell.
Struts.xml settings:
<constant name="struts.convention.default.parent.package" value="restful"/>
<package name="restful" extends="rest-default, struts-default, json-default">
<result-types>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
<result-type name="json" class="com.googlecode.jsonplugin.JSONResult"/>
</result-types>
....
</package>
I have setup the extra result types to be used on specific actions later. In the action class you can then setup your result types by action or method.
Action Class:
#Results({
#Result(name = "JsonSuccess", type = "json"),
#Result(name = "success", type = "tiles", location = "/tickets.tiles")
})
public class EventController extends RestActionSupport implements ModelDriven<EventBean>{
...
}
Something else to note about json results, I've noticed that when I have a serializable object being returned as a result, if that object contains other complex objects with a getter/setter that returns the embedded object, I will often receive an empty result or no result. I often end up writing json wrapper objects to use for my json results with getters/setters that only return java types (String, int, Boolean, etc) and not the embedded objects. I think that've solved this using delegate getters/setters but I'll have to go back and look at some old code.
Related
I find myself working a grails application that is being deployed as a fat jar built by a custom plugin that uses dropwizard to configure jetty.
It seems as though dropwizard doesn't allow facilitate the use of a plain old web.xml or jetty.xml and instead everything is set by java config at startup (i.e. using com.yammer.dropwizard.config.Environment).
Am I missing something here? Is there some way to map a 404 back to a URL or any kind of web page I can override so that a Jetty 404 isn't the default.
(yes I'm aware I could do something with the load balancer to redirect 404s)
I dont know how it is in grails, but this helps in java with dropwizard 0.7.1 run() method:
ResourceConfig jrConfig = environment.jersey().getResourceConfig();
environment.jersey().register(new RestErrorsHandler(jrConfig ));
Create this class for the mapping of exceptions -> give back an individual response!
#Provider
public class RestErrorsHandler implements ExceptionMapper<Exception> {
/**
* Deletes all ExpetionMappers.
*
* #param jrConfig
*/
public RestErrorsHandler(
ResourceConfig jrConfig)
{
// Remove all of Dropwizard's custom ExceptionMappers
Set<?> dwSingletons = jrConfig.getSingletons();
List<Object> singletonsToRemove = new ArrayList<Object>();
for (Object s : dwSingletons) {
// Remove all Exception mappers
if (s instanceof ExceptionMapper) {
singletonsToRemove.add(s);
}
}
for (Object s : singletonsToRemove) {
jrConfig.getSingletons().remove(s);
}
}
public Response toResponse(
Exception exception)
{
//Handle different exceptions in another way
if (exception.getClass().equals(JsonParseException.class)){
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
} else if(exception.getClass().equals(JsonParseException.class)){
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
} else if(exception.getClass().equals(Class.class)){
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
}
//genral problem -> output default
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
}
public static Response generalResponse(Exception exception)
{
return Response.status(Status.BAD_REQUEST).type(MediaType.TEXT_PLAIN)
.entity("if you just want to give back a string, but could also be default html page or whatever").build();
}
}
I am trying to find a solution to validate if XML data sent in a POST request are fulfilling a given custom XML schema.
If I use the XmlMediaTypeFormatter delivered with ASP.NET Web API I don't have a schema validation available, as far as I can see. For example: If I have a model type...
public class Order
{
public string Code { get; set; }
public int Quantity { get; set; }
}
...and a POST action in an ApiController...
public HttpResponseMessage Post(Order order)
{
if (ModelState.IsValid)
{
// process order...
// send 200 OK response for example
}
else
// send 400 BadRequest response with ModelState errors in response body
}
...I can post the following "wrong" XML data and will get a 200 OK response nevertheless:
User-Agent: Fiddler
Host: localhost:45678
Content-Type: application/xml; charset=utf-8
<Order> <Code>12345</Nonsense> </Order> // malformed XML
Or:
<Order> <CustomerName>12345</CustomerName> </Order> // invalid property
Or:
<Customer> <Code>12345</Code> </Customer> // invalid root
Or:
"Hello World" // no XML at all
etc., etc.
The only point where I have a validation of the request is model binding: In request example 1, 3 and 4 the order passed into the Post method is null, in example 2 the order.Code property is null which I could invalidate by testing for order == null or by marking the Code property with a [Required] attribute. I could send this validation result back in the response with a 400 "BadRequest" Http status code and validation messages in the response body. But I cannot tell exactly what was wrong and can't distinguish between the wrong XML in example 1, 3 and 4 (no order has been posted, that's the only thing I can see) - for instance.
Requiring that an Order has to be posted with a specific custom XML schema, for example xmlns="http://test.org/OrderSchema.xsd", I would like to validate if the posted XML is valid with respect to this schema and, if not, send schema validation errors back in the response. To achieve this I have started with a custom MediaTypeFormatter:
public class MyXmlMediaTypeFormatter : MediaTypeFormatter
{
// constructor, CanReadType, CanWriteType, ...
public override Task<object> ReadFromStreamAsync(Type type, Stream stream,
HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
var task = Task.Factory.StartNew(() =>
{
using (var streamReader = new StreamReader(stream))
{
XDocument document = XDocument.Load(streamReader);
// TODO: exceptions must the catched here,
// for example due to malformed XML
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(null, "OrderSchema.xsd");
var msgs = new List<string>();
document.Validate(schemaSet, (s, e) => msgs.Add(e.Message));
// msgs contains now the list of XML schema validation errors
// I want to send back in the response
if (msgs.Count == 0)
{
var order = ... // deserialize XML to order
return (object)order;
}
else
// WHAT NOW ?
}
});
return task;
}
}
This works so far as long as everything is correct.
But I don't know what to do if msgs.Count > 0. How can I "transfer" this validation result list to the Post action or how can I create a Http response that contains those XML schema validation messages?
Also I am unsure if a custom MediaTypeFormatter is the best extensibility point for such a XML schema validation and if my approach isn't the wrong way. Would possibly a custom HttpMessageHandler/DelegatingHandler be a better place for this? Or is there perhaps something much simpler out of the box?
If I were doing this I wouldn't use the Formatter. The primary goal of a formatter is to convert a wire representation to a CLR type. Here you have an XML document that you want to validate against a schema which is a different task altogether.
I would suggest creating a new MessageHandler to do the validation. Derive from DelegatingHandler and if the content type is application/xml load the content into XDocument and validate. If it fails, then throw a HttpResponseException.
Just add your MessageHandler to the Configuration.MessageHandlers collection and you are set.
The problem with using a derived XmlMediaTypeFormatter is that you are now executing at some point embedded inside the ObjectContent code and it is likely to be tricky to cleanly exit out. Also, making XmlMediaTypeFormatter any more complex is probably not a great idea.
I had a stab at creating the MessageHandler. I did not actually try running this code, so buyer beware. Also, the task stuff gets pretty hairy if you avoid blocking the caller. Maybe someone will clean that code up for me, anyway here it is.
public class SchemaValidationMessageHandler : DelegatingHandler {
private XmlSchemaSet _schemaSet;
public SchemaValidationMessageHandler() {
_schemaSet = new XmlSchemaSet();
_schemaSet.Add(null, "OrderSchema.xsd");
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
if (request.Content != null && request.Content.Headers.ContentType.MediaType == "application/xml")
{
var tcs = new TaskCompletionSource<HttpResponseMessage>();
var task = request.Content.LoadIntoBufferAsync() // I think this is needed so XmlMediaTypeFormatter will still have access to the content
.ContinueWith(t => {
request.Content.ReadAsStreamAsync()
.ContinueWith(t2 => {
var doc = XDocument.Load(t2.Result);
var msgs = new List<string>();
doc.Validate(_schemaSet, (s, e) => msgs.Add(e.Message));
if (msgs.Count > 0) {
var responseContent = new StringContent(String.Join(Environment.NewLine, msgs.ToArray()));
tcs.TrySetException(new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.BadRequest) {
Content = responseContent
}));
} else {
tcs.TrySetResult(base.SendAsync(request, cancellationToken).Result);
}
});
});
return tcs.Task;
} else {
return base.SendAsync(request, cancellationToken);
}
}
By trial and error I found a solution (for the WHAT NOW ? placeholder in the question's code):
//...
else
{
PostOrderErrors errors = new PostOrderErrors
{
XmlValidationErrors = msgs
};
HttpResponseMessage response = new HttpResponseMessage(
HttpStatusCode.BadRequest);
response.Content = new ObjectContent(typeof(PostOrderErrors), errors,
GlobalConfiguration.Configuration.Formatters.XmlFormatter);
throw new HttpResponseException(response);
}
...with the response class like this:
public class PostOrderErrors
{
public List<string> XmlValidationErrors { get; set; }
//...
}
That seems to work and the response looks like this then:
HTTP/1.1 400 Bad Request
Content-Type: application/xml; charset=utf-8
<PostOrderErrors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<XmlValidationErrors>
<string>Some error text...</string>
<string>Another error text...</string>
</XmlValidationErrors>
</PostOrderErrors>
I use a Struts2 Convention plug-in to map my actions. Please, help me to solve the following problem. Here I have an action mapping
#Action(value="/{categorie:\\w+}/{hoofdgroep:\\w+}/{artikelgroep:\\w+}/", results = {
#Result(name="success", location="articlelist.jsp"),
#Result(name="maingroup", location="/%{categorie}/%{hoofdgroep}/", type="redirect"),
#Result(name="category", location="/%{categorie}/", type="redirect")
}, interceptorRefs = {
...
})
public String execute() throws Exception {
...
Category category = service.getCategory(categorie);
if (category == null) return NONE;
...
MainGroup mGroup = service.getMainGroup(hoofdgroep);
if (mGroup == null) return "category";
...
ArticleGroup artGroup = service.getArticleGroup(artikelgroep);
if (artGroup == null) return "maingroup";
...
return SUCCESS;
}
When, for instance, there is no artGroup for specified artikelgroep it should redirect link _http://site/categorie/hoofdgroep/artikelgroep/ to url _http://site/categorie/hoofdgroep/ which it perfectly does. The only problem here is that it also prepends additional parameters which are undesired. So link _http://site/categorie/hoofdgroep/artikelgroep/ is redirected to _http://site/categorie/hoofdgroep/?categorie=categorie&hoofdgroep=hoofdgroep&artikelgroep=artikelgroep.
My question is How to get rid of these parameters?
Here are some config params from my struts.properties file
...
struts.serve.static=false
struts.ognl.allowStaticMethodAccess=true
struts.enable.DynamicMethodInvocation=false
struts.action.extension= ,
struts.url.includeParams=none
struts.enable.SlashesInActionNames=true
struts.mapper.alwaysSelectFullNamespace=false
struts.patternMatcher=regex
struts.convention.default.parent.package=app-default
struts.convention.action.packages=...
struts.convention.action.alwaysMapExecute=false
struts.convention.package.locators.disable=true
struts.convention.relative.result.types=dispatcher
struts.convention.result.path=/WEB-INF/jsp/
So basically is this a bug or it should work this way?
Perhaps it is not so elegant solution but here what I have done. I overrode org.apache.struts2.dispatcher.ServletRedirectResult#getProhibitedResultParams
public class ServletRedirectResult
extends org.apache.struts2.dispatcher.ServletRedirectResult
{
public ServletRedirectResult() {
super();
initProhibitedResultParams();
}
public ServletRedirectResult(String location) {
super(location);
initProhibitedResultParams();
}
public ServletRedirectResult(String location, String anchor) {
super(location, anchor);
initProhibitedResultParams();
}
private List<String> prohibitedParamNames;
private void initProhibitedResultParams() {
String[] parentParams = (String[])super.getProhibitedResultParams().toArray();
int len = parentParams.length;
String[] params = new String[len + 4];
for (int i = 0; i < len; i++) {
params[i] = parentParams[i];
}
params[len] = "statusCode";
// TODO: This is a temporary solution because RegexPatternMatcher puts parameters
// from urls into ResultConfig for some reason.
params[len+1] = "categorie";
params[len+2] = "hoofdgroep";
params[len+3] = "artikelgroep";
prohibitedParamNames = Arrays.asList(params);
}
protected List<String> getProhibitedResultParams() {
return prohibitedParamNames;
}
}
What you describe is the default behaviour of both com.opensymphony.xwork2.util.NamedVariablePatternMatcher and org.apache.struts2.util.RegexPatternMatcher however it not the behaviour of com.opensymphony.xwork2.util.WildcardHelper (which is the default implementation)
From what you have shown the default implementation can handle what you are doing with far less headaches (regular wildcard matching).
Consulting this page: http://struts.apache.org/2.3.1.2/docs/wildcard-mappings.html
It states for "Parameters in namespaces" (I know you are not using this):
From Struts 2.1+ namespace patterns can be extracted as request
parameters and bound to the action.
However this equally applies to what is happening in the action and it really seems to be the only behaviour (where I would assume from "can be" that there would be another choice when it should have really been written as "... namespace/action patterns are extracted as request parameters...") and it seems to apply to the regex pattern matching equally, it would be nice for the documentation to more explicitly state this.
From your comments I can better understand what you are doing...
Why don't you simply set up three actions for:
*/*/*, */* and *
Then just pass the numbered parameters into the action?
I was digging into the code of org.apache.struts2.dispatcher.ServletRedirectResult#doExecute. Probably this piece prepends undesired parameters
ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(invocation.getResultCode());
if (resultConfig != null)
{
Map<String, String> resultConfigParams = resultConfig.getParams();
for (Map.Entry<String, String> e : resultConfigParams.entrySet())
{
if (!getProhibitedResultParams().contains(e.getKey()))
{
String potentialValue = e.getValue() == null ? "" : conditionalParse(e.getValue(), invocation);
if (!suppressEmptyParameters || ((potentialValue != null) && (potentialValue.length() > 0)))
{
requestParameters.put(e.getKey(), potentialValue);
}
}
}
}
There is nothing wrong with this code. And the question is Why those three parameters appeared in the ResultConfig? Because it is working like, when you write like so
<result name="maingroup" type="redirect">
<param name="location">/${categorie}/${hoofdgroep}/</param>
<param name="namespace">/</param>
<param name="categorie">${categorie}</param>
<param name="hoofdgroep">${hoofdgroep}</param>
<param name="artikelgroep">${artikelgroep}</param>
</result>
I have a controller action that does some work in the database and then exits when it's finished. This action is being called via jQuery's ajax function with the dataType set to 'json'.
If I set the return type of the action to void, everything will function just fine except Firefox will show an error in the console that says: "no element found".
It makes sense that Firefox would throw this error if it was expecting XML to come back. However, even when I change the dataType property of the ajax call to "text", I still receive the error. In order to get rid of the error with the return type void, I would have to set the Response's ContentType to "text/html". Or I could set the return type to JsonResult and return a new [empty] JsonResult object.
I'm sure there are several ways I can make this error go away, but I wanted to know the proper way to handle actions with no return values being called via ajax.
If it matters, I'm also using the async controller action pattern.
public void DoSomethingAsync(SomeJsonObjectForModelBinding model)
{
// do some database things
}
public void DoSomethingCompleted()
{
// nothing to do...
// what should my return type be?
// do I need to set the content type here?
}
I know this doesn't exactly answer your question, but I would argue that you should always have a return value coming back from an AJAX or web service call. Even if only to tell you that the operation was successful, or otherwise return the error (message) back to you.
I often define a class like this:
public class JsonResultData
{
private bool _success = true;
public bool Success
{
get { return _success; }
set { _success = value; }
}
public object Value { get; set; }
public List<string> Errors { get; set; }
public JsonResultData()
{
this.Errors = new List<string>();
}
}
And then use it to return data or any other call meta data in the JsonResultData wrapper like so:
return new JsonResult {
Data = new JsonResultData { Value = returnValue, Success = true }
};
I can't comment because of my reputation but I still wanted to contribute to clear the confusion in Kon's answer.
In an application I caught all exceptions within an ActionMethod, set an HttpStatusCode and added an error message to the response. I extracted the message in the Ajax error function and showed it to the user.
Everything worked out fine until the application got put on the staging server, who had some kind of settings that did not allow a return message within an erroneous response. Instead some standard Html was transmitted resulting in a JS error processing the response.
In the end I had to rewrite all my exception handling returning my application errors as successful Ajax call (which it actually is) and then differ within the Ajax success function, just the way it should be.
You should not mix system-level and application-level feedback. You may not be able to control the system-level feedback the way your application needs.
I've developed a web site using Struts2 as a controller and integrated it with Spring and Hibernate to do the business logic and DB stuff. The website's URIs are http://my.domian.com/URI; which {URI} is dynamically generated thorough the admin cms. The mapping of each uri to the servlet are done with help of Apache mod_rewrite, as follow:
RewriteCond %{HTTP_HOST} ^www\.domain\.com
RewriteRule ^([a-zA-Z0-9_-]+)$ /dynamic\.action?f=$1 [QSA,L]
(Before any further information, is this a good and suitable approach?)
The struts configuration is just a typically-academic one as:
<package name="Default" extends="struts-default" namespace="/">
...
<action name="dynamic" class="DynamicContentAction">
<result name="index">/content/web/dynamic/index.jsp</result>
</action>
</package>
DynamicContentAction is extending ActionSupport and implementing ServletRequestAware, ServletContextAware. I'm checking a couple of things (such as a current visiting language which is identified as a subdomain), looking up in the database that the requested uri is valid or not, generating that uri's content and setting a couple of runtime global variables (such as current visiting page id, layout config due to current visiting language ...) and put it on a Request object in this servlet.
Everything looks good and even works perfectly ok, unless too many dynamic pages being requested by a single user concurrently. "Too Many" in my case is at least 9-10 pages. In this case it throws exceptions, different ones! Sometimes the HttpServletRequest request is null, sometimes ServletContext servletContext is null, some other times these are ok, but the runtime variables are null which is used in business logic or db querying.
I've googled about it and found out that this action is being instantiated "Per Request". Isn't this so? If there is an action per request, what's wrong with this conflict or "nullability thing". Should I do some thread-like thing in that action, beyond the threading of struts?
I'd be so appreciated if you could help me out or point me a direction.
Here is simplified version of DynamicContentAction.java
public class DynamicContentAction extends ActionSupport implements ServletRequestAware, ServletContextAware {
private HttpServletRequest request;
private ServletContext servletContext;
private ResourceSelectorService resourceSelectorService;
private String f = null;
public String execute() {
if ( f != null ) {
HashMap<String, Object> resolvedURI = resourceSelectorService.resolveURI(f);
if ( resolvedURI.get("ERROR").equals(true) ) {
//Generating nice 404 error page content
} else {
//Generating Content
//and put it on request object as:
//request.setAttribute("attrName", resourceContent);
}
}
else {
//Generating nice 404 error page content
}
request = null;
servletContext = null;
f = null;
return "index";
}
#Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void setF(String f) {
this.f = f;
}
public String getF() {
return f;
}
}
as I'm writing this post, I have came to the knowledge that this class is NOT thread-safe. Is it? So I've changed it a little bit as follow:
Here is newer version of DynamicContentAction.java
public class DynamicContentAction extends ActionSupport {
private ResourceSelectorService resourceSelectorService;
private String f = null;
public String execute() {
if ( f != null ) {
final HttpServletRequest request = ServletActionContext.getRequest();
final ServletContext servletContext = ServletActionContext.getServletContext();
HashMap<String, Object> resolvedURI = resourceSelectorService.resolveURI(f);
if ( resolvedURI.get("ERROR").equals(true) ) {
//Generating nice 404 error page content
} else {
//Generating Content
//and put it on request object as:
//request.setAttribute("attrName", resourceContent);
}
f = null;
}
else {
//Generating nice 404 error page content
}
return "index";
}
public void setF(String f) {
this.f = f;
}
public String getF() {
return f;
}
}
and the Null thing problem is almost gone, but there is still conflict with the generated content. For example if user try to open:
http:// www.domain.com/A
http:// www.domain.com/B
http:// www.domain.com/C
http:// www.domain.com/D
http:// www.domain.com/E
simultaneously, all of the pages will be rendered in browser, but the content of A is shown in A and B, C is correct, and there is a very good chance that the content of D and E are incorrect too.