I have a wicket contact form, and i receive the form object. Now i need to pass this object to Spring Service.
package com.mysticcoders.mysticpaste.web.pages;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import com.mysticcoders.mysticpaste.model.Contact;
import org.apache.wicket.model.CompoundPropertyModel;
import com.mysticcoders.mysticpaste.services.IContact;
public class FormPage extends WebPage
{
private Contact contact;
private IContact icontact;
public FormPage()
{
// Add a FeedbackPanel for displaying our messages
FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
add(feedbackPanel);
Form<Object> form = new Form<Object>("contactForm",
new CompoundPropertyModel<Object>(contact))
{
private static final long serialVersionUID = 1L;
protected void onSubmit(Contact contact)
{
icontact.saveContact(contact);
}
};
form.add(new TextField<Object>("name"));
form.add(new TextField<Object>("email"));
form.add(new TextField<Object>("country"));
form.add(new TextField<Object>("age"));
add(form);
// add a simple text field that uses Input's 'text' property. Nothing
// can go wrong here
}
}
I am pretty much sure that we need to do something with application-context xml where i may need to wire out.
My Application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="WicketApplication" class="com.mysticcoders.mysticpaste.web.pages.WicketApplication" />
</beans>
My Question is simple.
What should i do which can make my
onSubmit method call the Spring
Service?
Could someone let me know what needs
to modified in my
Application-context.xml so that once
the form gets submitted, it contacts
the Spring Service class.
Wicket-Spring integration shows various ways on how to inject Spring Beans (e.g. your IContactService bean) into Wicket pages.
Basically, after configuration of the component injector, you end up with the following code:
public class FormPage extends WebPage
{
#SpringBean
private IContact icontact;
...
Form<Object> form = new Form<Object>("contactForm",
new CompoundPropertyModel<Object>(contact))
{
private static final long serialVersionUID = 1L;
protected void onSubmit(Contact contact)
{
icontact.saveContact(contact);
}
};
The #SpringBean answer by mhaller is of course valid and considered a best practice by many. But I prefer a more standard Spring approach, where your Wicket Application has the services you need.
public class YourWicketApp extends WebApplication{
public static YourWicketApp get(){
return (YourWicketApp) Application.get();
}
private ServiceA serviceA;
// getter and setter for serviceA here
}
Now in your component, call
YourWicketApp.get().getServiceA();
There are of course some drawbacks, the biggest one being that you can't easily test such a component without the application.
Related
I have the next simple application(class Message has only one method which prints incoming message and has no interest for the question):
package messager.spring;
public class User {
private Messenger misiger;
private String name;
public User(String name) {
this.name = name;
}
public void setMessenger(Messenger messinger) {
this.misiger = messinger;
}
public void send(String mess) {
String message = name + " sent message " + "'" + mess + "'";
misiger.send(message);
}
// public String getname() {
// return name;
// }
}
Main class:
package messager.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
user.send("testing3...");
}
}
Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="user" class="messager.spring.User" autowire="byName">
<constructor-arg type="java.lang.String" value="Vova2"/>
</bean>
<bean id="messenger" class="messager.spring.MobileMessenger"/>
</beans>
I used autowiring for class User autowiring Messanger class. According to documentation :
When ByName is used, it then tries to match and wire its properties with the beans defined by the same names in the configuration file. If matches are found, it will inject those beans otherwise, it will throw exceptions.
This configuration works but I dont understand why((( I dont have property with name messenger inside User class((( I changed it on purpose to misiger. And it still works. It seems that bean id directly depends not on property name, but on setter name!!! Is it so?
YES, you are right. As described here :
Spring will lowercase the first letter after “set” in the method name and use the rest of the method name as-is for deducing the property name.
So not the member variable but the setter defines the property name.
That's how JavaBeans work, by looking at naming conventions.
The underlying reference isn't necessarily relevant.
The name of your property is messenger because there's a getter called that.
I'm flying a CXF-based Web service not unsimilar to the example on the CXF Web site at http://cxf.apache.org/docs/jax-ws-configuration.html . This service has an implemented endpoint based on the following sample context:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint id="myServiceMembersImpl"
implementor="#myService"
endpointName="e:MyServiceMembersEndpoint"
serviceName="s:MyServiceMembersService"
address="http://localhost:8080/myservicemembers"
xmlns:e="http://localhost:8080/myservicemembers/ns"
xmlns:s="http://localhost:8080/myservicemembers/ns"/>
</beans>
Then, of course, there is the Java ...
Interface:
package com.me.service;
#WebService
public interface MyService {
String MEMBER = "MEMBER";
#WebResult(name = MEMBER)
Member getMember(#WebParam(name = "memberId") long memberId) throws Exception;
// ...
// more interface declarations
// ...
} // end interface
and, implementation:
package com.me.service.impl;
#WebService(endpointInterface = "com.me.service.MyService")
#Path("/")
public class MyServiceMembersImpl implements MyService {
#GET
#Path("/{id}")
#Consumes({ APP_JSON, APP_XML })
#Produces({ APP_JSON, APP_XML })
#Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public Member getMember(#PathParam("id") final long memberId) throws Exception {
// ...
// business logic
// ...
return theMember;
} // end method
} // end class
Which returns a WSDL that starts somewhat like this:
<?xml version="1.0" encoding="UTF-8" ?>
<wsdl:definitions name="MyServiceImplService"
targetNamespace="http://localhost:8080/myservicemembers/ns"
xmlns:ns1="**http://service.me.com/**"
xmlns:ns2="http://schemas.xmlsoap.org/soap/http"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://localhost:8080/myservicemembers/ns"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:import location="http://localhost:8080/myservicemembers?wsdl=**MyService**.wsdl"
namespace="**http://service.me.com/**" />
<wsdl:binding name="MyServiceImplServiceSoapBinding" type="ns1:**MyService**">
<!-- ... -->
</wsdl:definitions>
It's fairly simple using the "jaxws:endpoint" element in the application context to change the settings for the endpoint. This fleshes out the service name, endpoint name and other fields. However, the top-level interface still has a say in the WSDL file. The STARRED items above are from the top-level interface. How can I inject values into the top-level interface for the targetNamespace and serviceName?
My good reasons for doing this include (1) not wanting to expose package names in the WSDL and (2) wanting to switch namespaces as an application moves down a deployment runway. Thus I cannot use annotations since those are compile-time values, I can't substitute them with property placeholders, and I will not recompile my code in the production tier.
You can do this by programmatically creating the services using JaxWsServerFactoryBean instead of using <jaxws:endpoint> in your Spring config. Doing the creation programmatically gives you a lot more control.
For example:
#Autowired
var myServiceImpl: MyService = _
val propMap = mutable.HashMap[String, AnyRef]("org.apache.cxf.logging.FaultListener"->faultListener.asInstanceOf[AnyRef])
val sf = new JaxWsServerFactoryBean
sf.setServiceBean(myServiceImpl)
sf.setAddress("/myservice")
sf.setServiceName(new QName(WEB_SERVICE_NAMESPACE, "myService", "MyService"))
sf.setProperties(propMap)
sf.create
I have a web application developped in Java 1.5 with Spring framework. Application contains "dashboards" which are simple pages where a bunch of information are regrouped and where user can modify some status. Managers want me to add a logging system in database for three of theses dashboards. Each dashboard has different information but the log should be traced by date and user's login.
What I'd like to do is to implement the Strategy pattern kind of like this :
interface DashboardLog {
void createLog(String login, Date now);
}
// Implementation for one dashboard
class PrintDashboardLog implements DashboardLog {
Integer docId;
String status;
void createLog(String login, Date now){
// Some code
}
}
class DashboardsManager {
DashboardLog logger;
String login;
Date now;
void createLog(){
logger.log(login,now);
}
}
class UpdateDocAction{
DashboardsManager dbManager;
void updateSomeField(){
// Some action
// Now it's time to log
dbManagers.setLogger = new PrintDashboardLog(docId, status);
dbManagers.createLog();
}
}
Appcontext.xml :
<bean id="dashboardManagers" class="...DashboardManagers" />
In this solution I'm therefore not using dependency injection. Is it "correct" (good practice, performance, ...) to do it this way ? Is there a better way where I could use DI ?
Note :I did not write basic stuff like constructors and getter/setter.
Your solution will create a new instance of PrintDashboardLog for each call to updateSomeField(). This might take up unnecessary time/memory/GC-effort. Also, from a design perspective it makes sense if there is one DashboardLog for each Dashboard, not a new one for each call.
I think it may be a good idea to use aspects for which Logging is one of the exemplary usecases. Something like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="loggingAspect" class="com.yourcompany.yourapplication.aspects.DashboardLogAspect" />
<aop:aspectj-autoproxy>
<aop:include name="loggingAspect" />
</aop:aspectj-autoproxy>
</beans>
package com.yourcompany.yourapplication.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class DashboardLogAspect {
#Around("execution(* com.yourcompany.yourapplication..*Action+.*(..)) && target(target)")
public Object logActionCall(ProceedingJoinPoint pjp, Object target) throws Throwable {
long before = System.nanoTime();
Object returnValue = pjp.proceed();
long after = System.nanoTime();
long durationNs = after - before;
String logMsg = target.getClass() + "." + pjp.getSignature().toShortString() + " (" + durationNs + " ns)";
// TODO: store the log message in your database
System.out.println(logMsg);
return returnValue;
}
}
This logs all calls to application classes with a name ending in 'Action'. It also adds the time each call took to complete. You might want to tweak the Around advice for a specific method name pattern as well. See the AspectJ programming guide
While it is perfectly "correct" to employ the strategy pattern as you have, but considering the fact that you're using Spring - it would be better to employ the Dependency Injection mechanism provided by the Spring framework - might as well put to use what your framework has to offer as one of its core strengths.
If each "dashboard" is has a controller, why not call the logging from the controller.
public interface DashboardLog
{
void createLog(...);
}
public class DashboardUno
implements DashboardLog
{
...
public void createLog(...)
{ ... }
}
#Controller
#RequestMapping("/blah/schmarr")
public class BlahController
{
...
#RequestMapping(value = "/xxx")
public String someMeaningfulName(...)
{
DashboardUno elEsUno;
... get the dashboard object ...
elEsUno.createLog(...);
...
}
}
I am developing RESTful API for my application. All getters (that use HTTP GET) work fine. I cannot make save method (that uses POST) to work.
I am using HTML form and RESTClient for testing.
Here is my Controller
#Controller
public class EntitiesController {
#RequestMapping(value="/ci/save/", method = RequestMethod.POST)
public ModelAndView saveConfigurationItem(#RequestBody ConfigurationItem body) {
System.out.println("saveConfigurationItem: body=" + body);
return createModelAndView("ci", Collections.emptyList());
}
}
This method is expected to be called when client posts ConfigurationItem.
I am using custom serialization format. It is not XML or JSON. It is VCard or VCalendar format. For my first test I used the following VCard:
BEGIN:VCARD
N:Pooh;Winnie
FN:Winnie the Pooh
TEL:tel:+441234567
END:VCARD
I posted it to URL http://localhost:8080/core.solution-1.0/data/ci/save/.
Here is the response I get:
415
The server refused this request because the request entity is in a format not
supported by the requested resource for the requested method ()
(*) ConfigurationItem is an abstract class. CardEntry extends it. I tried both.
I tried to change the method parameter to String. In this case the method is called but the string is empty. The same happens when following one of recommendations I saw in web I changed the parameter type to MultiValueMap and sent request from simple HTML form.
I saw that marshal() is not called at all.
What's wrong?
Here is what I have. (I put here relevant code only.)
Spring configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<import resource="classes/spring-config-prod.xml"/>
<context:component-scan base-package="com.mycompany.solution.service" />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="ciCardView" class="com.mycompany.solution.service.VFormatView">
<constructor-arg>
<bean class="com.mycompany.solution.service.VFormatMarshaller">
<property name="packagesToScan" value="com.mycompany.solution.entity"/>
</bean>
</constructor-arg>
</bean>
</beans>
Marshaller
public class VFormatMarshaller implements Marshaller, Unmarshaller {
#Override
public void marshal(Object obj, Result result)
throws IOException/*, XmlMappingException*/ {
System.out.println("VFormatMarshaller.marshal(" + obj + ")");
marshalStreamResult(obj, (StreamResult)result);
}
#Override
public boolean supports(Class<?> paramClass) {
System.out.println("VFormatMarshaller.supports(" + paramClass + ")");
boolean supports = new HashSet<String>(Arrays.asList(packagesToScan)).contains(paramClass.getPackage().getName());
if (supports) {
return supports;
}
return Collection.class.isAssignableFrom(paramClass);
}
#Override
public Object unmarshal(Source source) throws IOException/*, XmlMappingException*/ {
System.out.println("VFormatMarshaller.unmarshal(" + source + ")");
return unmarshalStreamSource((StreamSource)source);
}
//// .............................
}
View (this is written only to override the content type)
public class VFormatView extends MarshallingView {
public VFormatView() {
super();
setContentType("application/vcard");
System.out.println("VFormatView()");
}
public VFormatView(Marshaller marshaller) {
super(marshaller);
setContentType("application/vcard");
System.out.println("VFormatView(" + marshaller + ")");
}
}
#RequestBody/#ResponseBody are supported by an hierarchy of HttpMessageConverters, that is completely different from ViewResolvers.
In you case you need to configure a MarshallingHttpMessageConverter with appropriate marshaller/unmarshaller and content type (or create your own HttpMessageConverter if you don't need to depend on the existing implementation of marshaller/unmarshaller), and supply a configured instance to AnnotationMethodHandlerAdapter.
The least intrusive way to configure a custom HttpMessageConveter is to create a BeanPostProcessor as follows:
public class Configurer implements BeanPostProcessor {
public void postProcessAfterInitialization(String name, Object bean) {
if (bean instanceof AnnotationMethodHandlerAdapter) {
AnnotationMethodHandlerAdapter a = (AnnotationMethodHandlerAdapter) bean;
HttpMessageConverter[] convs = a.getMessageConverters();
... add new converter ...
a.setMessageConverters(convs);
}
}
...
}
I'm new to Spring, and I'm curious as to how to approach validating form input against a data source. I'm using Spring 3.0.3, by the way. So lets say I have the following form:
public class MyForm {
private String format;
public String getFormat() {
return format;
}
public void setFormat( value:String ) {
format = value;
}
}
Now lets say the format property is a string representation of a file format: "jpg", "png", "gif", "bmp", etc. Naturally I thought to write a validator for the form. It looks something like this:
public class MyFormvalidator implements Validator
{
#Override
public boolean supports( Class<?> clazz ) {
return MyForm.class.equals( clazz );
}
#Override
public void validate( Object obj, Errors errors ) {
MyForm myForm = (MyForm) obj;
ValidationUtils.rejectIfEmptyOrWhitespace( errors, "format", "error.required" );
if( !myForm.getFormat().equals( "jpg" ) &&
!myForm.getFormat().equals( "png" ) &&
.... etc .... ) {
errors.rejectValue( "format", "error.invalid" );
}
}
}
So thats all fine and dandy, but lets say I want to add new supported formats without having to adjust my validator, recompile, and deploy it. Rather than get into database 'n what not, lets keep it simple go with a little XML file that could be modified. It would look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<fileformats>
<item>jpg</item>
<item>png</item>
.... etc ....
</fileformats>
And finally, the real point of all this...what should my approach be to making this data available during the validation of the form input?
The easiest way to do this is to make the Validator a Spring bean, and put the list of formats in your Spring configuration:
public class MyFormvalidator implements Validator
{
private List<String> fileFormats;
public MyFormValidator(List<String> fileFormats) {
this.fileFormats = fileFormats;
}
... //the rest of your validator, including checks for fileFormats.contains(myForm.getFormat())
Now, in your Spring configuration, you have
<bean name="myFormValidator" class="something.something.MyFormValidator">
<constructor-arg>
<list>
<value>jpg</value>
<value>png</value>
... etc ...
</list>
</constructor-arg>
</bean>
Do you consider changes to the application context source changes? You can create a list in your bean definition and inject it right into the validator.
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="myValidator"
class="MyValidator>
<property name="acceptedExtensions"/>
<util:set>
<value>jpg</value>
<value>png</value>
</util:set>
</property>
</bean>
</beans>
public class MyFormvalidator
implements Validator {
private Set<String> acceptedExtensions;
public void setAcceptExtensions(Set<String> extensions) {//etc}
#Override
public void validate( Object obj, Errors errors ) {
MyForm myForm = (MyForm) obj;
ValidationUtils.rejectIfEmptyOrWhitespace(
errors, "format", "error.required" );
if( !acceptedExtensions.contains(myForm.getFormat){
errors.rejectValue( "format", "error.invalid" );
}
}