Recently I have encounter a problem with the web application. I'm using the spring mvc restful application together with hibernate as jpa.
The client could build a xml file using this format:
<SCCF>
<registerSCCF>...</registerSCCF>
...
<registerSCCF>...</registerSCCF>
</SCCF>
The web app will then mapping every data inside registerSCCF tag to a class and save it in the database.
Now I am suffering with the problem that when i test it using soapui and multithreading test, i always get the exception
[ERROR] an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: null id in draft.persistence.entity.dcrm.CustomersNoneSSO entry (don't flush the Session after an exception occurs)
or
Caused by: org.hibernate.HibernateException: Flush during cascade is dangerous
or
org.hibernate.SessionException: Session is closed!
Here is the service layer code:
#Transactional("dcrm")
public boolean postSCCFService(SCCFVO sccf){
CustomersNoneSSO cns = new CustomersNoneSSO();
cns.setAppid(sccf.getAppid());
cns.setCustomer_name(sccf.getCustomer_name());
cns.setCustomer_gender(sccf.getCustomer_gender());
cns.setContact_mobile(sccf.getContact_mobile());
cns.setContact_email(sccf.getContact_email());
cns.setAddress_province(sccf.getAddress_province());
cns.setAddress_city(sccf.getAddress_city());
cns.setCustomer_address(sccf.getCustomer_address());
cns.setCustomer_occupation(sccf.getCustomer_occupation());
cns.setPurchase_brand(sccf.getPurchase_brand());
cns.setPurchase_model(sccf.getPurchase_model());
cns.setPurchase_date(sccf.getPurchase_date());
cns.setPurchase_budget(sccf.getPurchase_budget());
cns.setOwncar_selected(sccf.getOwncar_selected());
cns.setOwncar_model(sccf.getOwncar_model());
cns.setTestdrive_permission(sccf.getTestdrive_permission());
cns.setMarketing_permission(sccf.getMarketing_permission());
Timestamp t = new Timestamp(new Date().getTime());
cns.setInsert_timestamp(t);
cns.setUpdate_timestamp(t);
cnsDao.makePersistent(cns);
}
if i set all the setter to static values like:
cns.setContact_email("test#test.test");
instead of using the value from the parameter, then the app runs well with the multithreading test.
There is the controller calls the service method:
#RequestMapping(value = "/test",method=RequestMethod.POST)
public #ResponseBody SCCFResponseList getPostResults(#RequestBody SCCFVOList sccf){
...
for(SCCFVO sccfvo : sccf.getSCCFVOList()){
...
boolean result = sccfservice.postSCCFService(sccfvo);
...
}
...
}
public class SCCFVOList {
And here is the request body class:
#XmlElement(name="registerSCCF")
public class SCCFVOList {
private Vector<SCCFVO> SCCFVOList = null;
public Vector<SCCFVO> getSCCFVOList(){
return SCCFVOList;
}
public void setSCCFVOList(Vector<SCCFVO> SCCFVOList){
this.SCCFVOList = SCCFVOList;
}
}
And here the dao
public class CNSDao extends GenericHibernateDAO<CustomersNoneSSO, Long> {}
public abstract class GenericHibernateDAO<T, ID extends Serializable>
implements GenericDAO<T, ID> {
private Class<T> persistentClass;
private Session session;
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public GenericHibernateDAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
#SuppressWarnings("unchecked")
public void setSession(Session s) {
this.session = s;
}
protected Session getSession() {
session = sessionFactory.getCurrentSession();
if (session == null)
throw new IllegalStateException(
"Session has not been set on DAO before usage");
return session;
}
public Class<T> getPersistentClass() {
return persistentClass;
}
#SuppressWarnings("unchecked")
public T makePersistent(T entity) {
getSession().saveOrUpdate(entity);
return entity;
}
public void makeTransient(T entity) {
getSession().delete(entity);
}
...
}
There should be something wrong either the controller method or the service method. Still no idea what was wrong.
Your dao is flawed.
Your dao is a singleton, there is only one. The Hibernate Session object isn't thread safe and shouldn't be used across threads.
You have 1 dao, 2 threads, Thread one gets instance X1 of a session, Thread two resets it to instance X2 now suddenly they share the same session, not to mention Thread 1 might even be operating on 2 different sessions.
As I mentioned in the comments NEVER store the Session in an instance variable. Remove it.
public abstract class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {
private Class<T> persistentClass;
private SessionFactory sessionFactory;
public GenericHibernateDAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
Also I would suggest dropping this and instead use Spring Data JPA saves you the trouble of creating and maintaining your own generic dao. (You mention you use JPA, if the entities are annotated it should be quite easy to do).
Related
I get the json value using the retrofit library at application launch and I want to send it to the global variable in the class. How can I do it?
Domain is coming, I can see it on the screen with toast message
public void onCreate() {
setRetrofitSettings();
}
public void setRetrofitSettings(){
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
timeApi = retrofit.create(TimeApi.class);
timeTurkeyCall = timeApi.getTime();
timeTurkeyCall.enqueue(new Callback<TimeTurkey>() {
#Override
public void onResponse(Call<TimeTurkey> call, Response<TimeTurkey> response) {
if (response.isSuccessful()){
timeTurkey = response.body();
Global.APIURL = String.valueOf(timeTurkey.getDateTime());
// I want to send the value here.
}
}
#Override
public void onFailure(Call<TimeTurkey> call, Throwable t) {
System.out.println(t.toString());
}
});
}
I want to send post value to global class
I want the incoming data to be assigned to the API_URL variable from here
public class Global {
public static final String API_URL;
}
I want the incoming domain to be active as long as the application is open.
I want to implement a mechanism in a custom webview client (without JavaScript injection) that can block ads. Is a way I can catch ads and replace them with other ads from a trusted source?
Thanks
In your custom WebViewClient, you can override the function shouldInterceptRequest(WebView, WebResourceRequest).
From Android docs:
Notify the host application of a resource request and allow the application to return the data.
So the general idea is to check if the request is coming from an ad URL (plenty of black list filters out there), then return a "fake" resource that isn't the ad.
For a more in depth explanation plus an example, I recommend checking out this blog post.
To implement this, you have two options:
Use Javascript injected code to do this (which you explicitely said, don't want)
In WebView, instead of "http://example.com" load "http://myproxy.com?t=http://example.com" (properly escaped, of course) and setup "myproxy.com" to be a proxy which will fetch the upstream page (given in "t" query parameter, or in any other way) and replace ads with the trusted ones before sending response to the client. This will be pretty complex, though, because ads can be in many forms, they're usually Javascript injected themselves and you'd probably need to rewrite a lot of URL's in the fetched HTML, CSS and JS files etc.
I made a custom WebViewClient like:
public class MyWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) { }
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith(".mp4")) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "video/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
return true;
} else if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:")
|| url.startsWith("mms:") || url.startsWith("mmsto:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
private Map<String, Boolean> loadedUrls = new HashMap<>();
#SuppressWarnings("deprecation")
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
boolean ad;
if (!loadedUrls.containsKey(url)) {
ad = AdBlocker.isAd(url);
loadedUrls.put(url, ad);
} else {
ad = loadedUrls.get(url);
}
return ad ? AdBlocker.createEmptyResource() :
super.shouldInterceptRequest(view, url);
}
}
And created an AdBlocker class like:
public class AdBlocker {
private static final Set<String> AD_HOSTS = new HashSet<>();
public static boolean isAd(String url) {
try {
return isAdHost(getHost(url));
} catch (MalformedURLException e) {
Log.e("Devangi..", e.toString());
return false;
}
}
private static boolean isAdHost(String host) {
if (TextUtils.isEmpty(host)) {
return false;
}
int index = host.indexOf(".");
return index >= 0 && (AD_HOSTS.contains(host) ||
index + 1 < host.length() && isAdHost(host.substring(index + 1)));
}
public static WebResourceResponse createEmptyResource() {
return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes()));
}
public static String getHost(String url) throws MalformedURLException {
return new URL(url).getHost();
}
}
And use this WebViewClient in your oncreate like:
webview.setWebViewClient(new MyWebViewClient());
I'm dealing with a HttpSessionRequiredException and read about (https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc) how to catch it via the #ExceptionHandling annotation.
This does work since my breakpoint hits the spot. Unfortunately the string containing the view name does not trigger any view resolving and therefore no error page is being rendered.
Steps to Reproduce:
Open http://localhost:8080/manager (Session Attributes are being initialized)
Restart Web Application (Session/SessionAttributes are being reset)
Fill out form and press button (launches POST Request via AJAX - see Edit #2)
ExceptionHandler jumps in. Since a HttpSessionRequiredException is being thrown due the missing session attributes
Check Network Panel in Chrome which yields following information on the failed POST:
Controller Class incl. Exception Handler
#Controller
#Log
#RequestMapping(value = "/manager")
#SessionAttributes({"moduleDescriptors", "Environments", "moduleExecutionData"})
public class ManagerController {
private static final String MANAGER_VIEW = "manager";
private final ManagerHelper managerHelper;
private final ModuleExecution moduleExecution;
private final SystemProperties SystemProperties;
#Autowired
public ManagerController(ManagerHelper managerHelper, ModuleExecution moduleExecution,
SystemProperties SystemProperties) {
this.managerHelper = managerHelper;
this.moduleExecution = moduleExecution;
this.SystemProperties = SystemProperties;
}
#GetMapping
public ModelAndView render() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(MANAGER_VIEW);
modelAndView.addObject("moduleExecutionData", new ModuleExecutionData());
List<ModuleDescriptor> moduleDescriptorsFromServices = managerHelper.getModuleDescriptorsFromServices();
modelAndView.addObject("moduleDescriptors", moduleDescriptorsFromServices);
//TODO: Change varName for Systems
modelAndView.addObject("Environments", SystemProperties.getEnvironments());
log.info("Found " + moduleDescriptorsFromServices.size() + " module descriptors");
return modelAndView;
}
#PostMapping
public String execute(#ModelAttribute ModuleExecutionData moduleExecutionData) {
moduleExecution.execute(moduleExecutionData);
// sessionStatus.setComplete();
return MANAGER_VIEW;
}
#ExceptionHandler(HttpSessionRequiredException.class)
public String sessionError(){
return "sessionError";
}
}
My view lies within all the folder with all working views.
Any idea what I'm doing wrong? I'm configuring spring completely with annotations - not XML.
Edit:
I checked the response and saw that it actually returns the HTML of the View. But this HTML is not rendered. Is it because I made a POST request? Which actually ignores any return HTML?
But that does not make sense - because my original PostHandler does return a view as well and it is rendered.
PostHandler
#PostMapping
public String execute(#ModelAttribute ModuleExecutionData moduleExecutionData) {
moduleExecution.execute(moduleExecutionData);
return MANAGER_VIEW;
}
Edit #2
Here is the POST JavaScript Ajax logic
function postForm(event) {
const moduleId = $(event.currentTarget).data("module-id");
const formData = $("#" + moduleId).serialize();
$.ajax({
type: "post",
data: formData,
url: "/manager",
dataType: "json"
});
}
I have some ajax Behaviour that should pick some data using JS, and turn it back to Java. Sometimes it works but quite ofen it is just add url parameter and do page refresing/
public abstract class LoggedVKIdBehaviour extends AbstractDefaultAjaxBehavior {
private static final Logger logger = LoggerFactory.getLogger(LoggedVKIdBehaviour.class);
#Override
protected void respond(AjaxRequestTarget target) {
String loggedVkId = RequestCycle.get().getRequest().getRequestParameters().getParameterValue("logged_vkid").toString();
logger.info("ajax has comming with logged VK ID " + loggedVkId);
recived(target, loggedVkId);
}
protected abstract void recived(AjaxRequestTarget target, String loggedVkId);
#Override
public void renderHead(final Component component, IHeaderResponse response) {
super.renderHead(component, response);
Map<String, Object> map = new HashMap<>();
map.put("callbackFunction", getCallbackFunction(CallbackParameter.explicit("logged_vkid")));
//
PackageTextTemplate ptt = new PackageTextTemplate(LoggedVKIdBehaviour.class, "vkid_callback.js");
OnDomReadyHeaderItem onDomReadyHeaderItem = OnDomReadyHeaderItem.forScript(ptt.asString(map));
response.render(onDomReadyHeaderItem);
}
}
js template
var calback = ${callbackFunction};
var logged_vk_id = 11;
function authInfo(response) {
if (response.session) {
logged_vk_id = response.session.mid;
calback(response.session.mid);
console.log("recived callback from VK " + logged_vk_id);
}
}
$(document).ready(function () {
VK.Auth.getLoginStatus(authInfo);
});
it is do recursive redirection like http://localhost:8080/mytool/product/1?logged_vkid=332797331&logged_vkid=332797331&logged_vkid=332797331&logged_vkid=332797331&logged_vkid=332773...
As i understand Ajaj technology - iti asynchronus requests, that shouldn't touch main url at all. So what is the reason for page refreshing?
this is generated Callback function
function (logged_vkid) {
var attrs = {"u":"../wicket/bookmarkable/com.tac.kulik.pages.product.ProductPage?12-1.IBehaviorListener.0-&productID=1"};
var params = [{"name":"logged_vkid","value":logged_vkid}];
attrs.ep = params.concat(attrs.ep || []);
Wicket.Ajax.ajax(attrs);
}
I use wicket 7.2
I did a lot investigations for few days. And found that when i remove
setPageManagerProvider(new NoSerializationPageManagerProvider(this));
Application throw me exepton in polite logs
org.apache.wicket.WicketRuntimeException: A problem occurred while
trying to collect debug information about not serializable object look
like it is could come from aused by: java.io.NotSerializableException:
com.tac.kulik.panel.smaccounts.SMAccountsPanel$1
which means that page tryed to be serialized for SOME REASON but $1 it is mean Anonimous class. I had few class created anonimously to ges some ajax links coming from ListView to be managed on parent panel. So After removing this Anonimous class logic, everything start and run well.
So i am happy, but still don't understand which reason page did serialization after ajax, and what the reason was to refresh whole page.
I work on an application that using PhoneGap. For the moment, I only test it on Android. I have several pages in my application that need the geolocation feature.
So I made a JS to handle it with this line of code (of course it's not my unique line of code) :
navigator.geolocation.watchPosition(successGeolocation, errorGeolocation, {maximumAge: 5000, enableHighAccuracy: true});
The geolocation need to be the most accurate possible so I use the GPS and it can take some time to have a GPS Fix.
The problem is when the user navigates from one page to another. The WatchPosition stop (it's normal because the user load an other page) and when I recall it the GPS need to Fix again.
It's very annoying and I search a solution to keep the GPS active. Someone has an idea for me ? Maybe with a plugin or a native Android LoC I can keep it active during all the application life ?
Thanks.
First step you should create an Android plugin that will give you API for receiving the location data.
Creating a plugin is quite easy and is explained here:
Plugin Development Guide and Developing a Plugin on Android.
You can also see an example of creating a Cordova plugin here.
Next, create a location monitor class. You can make it singleton and initialize it from your main activity.
Here is a simple, but working code I compiled from several sources and many tests to fit my needs.
The main code is taken from here, though I simplified it as much as was possible.
public class LocationMonitor
{
private LocationListener locationListener = null;
private LocationManager locationManager = null;
private Location location = null;
public LocationMonitor()
{
}
public void startGPSActivity(Context context)
{
LocationLooper looper = new LocationLooper();
looper.start();
while (!looper.isReady())
{
}
looper.handler.post(new LocationBootstrapper(context));
}
public void stopGPSActivity()
{
locationManager.removeUpdates(locationListener);
}
public Location getLocation()
{
return location;
}
private class LocationLooper extends Thread
{
private Handler handler;
private LocationLooper()
{
}
public void run()
{
Looper.prepare();
this.handler = new Handler();
Looper.loop();
}
public boolean isReady()
{
return this.handler != null;
}
}
private class LocationBootstrapper implements Runnable
{
private Context context;
private LocationBootstrapper(Context context)
{
this.context = context;
}
public void run()
{
locationListener = new LocationListenerImpl();
locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, locationListener);
}
}
private class LocationListenerImpl implements LocationListener
{
private LocationListenerImpl()
{
}
#Override
public void onLocationChanged(Location location)
{
LocationMonitor.this.location = location;
Log.i("LocationMonitor", "New location: lat= " + location.getLatitude() + " lng=" + location.getLongitude() + " acc=" + location.getAccuracy());
}
#Override
public void onProviderDisabled(String provider)
{
}
#Override
public void onProviderEnabled(String provider)
{
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
}
Now access the LocationMonitor class from your plugin and you have your desired solution - page changes will not re-initialize your GPS and location data is available to your PhoneGap app.
Cheers