Categories
discuss

Native query and caching mechanism of Hibernate

I have a question regarding Hibernate caching mechanism.I have read in the articles that native SQLquery execution in hibernate, invalidates all regions of cache because hibernate does not have any idea regarding which particular entity it is going to affect. Here all regions of cache means are we talking about various regions of the second level cache or both levels of cache(first level cache,second level cache) or only second level cache or only first level cache?

Answer

Using SQLQuery, Hibernate couldn’t know what cache regions you might affect, but luckily you can explicitly instruct it:

SQLQuery sqlQuery = session.createSQLQuery(
    "UPDATE CUSTOMER SET ... WHERE ..."); 
sqlQuery.addSynchronizedEntityClass(Person.class); int
int updateCount = sqlQuery.executeUpdate();

This way it knows what query caches to invalidate, otherwise it may discard everything:

private static class EntityCleanup {
    private final EntityRegionAccessStrategy cacheAccess;
    private final SoftLock cacheLock;

    private EntityCleanup(EntityRegionAccessStrategy cacheAccess) {
        this.cacheAccess = cacheAccess;
        this.cacheLock = cacheAccess.lockRegion();
        cacheAccess.removeAll();
    }

    private void release() {
        cacheAccess.unlockRegion( cacheLock );
    }
}

private static class CollectionCleanup {
    private final CollectionRegionAccessStrategy cacheAccess;
    private final SoftLock cacheLock;

    private CollectionCleanup(CollectionRegionAccessStrategy cacheAccess) {
        this.cacheAccess = cacheAccess;
        this.cacheLock = cacheAccess.lockRegion();
        cacheAccess.removeAll();
    }

    private void release() {
        cacheAccess.unlockRegion( cacheLock );
    }
}

private class NaturalIdCleanup {
    private final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy;
    private final SoftLock cacheLock;

    public NaturalIdCleanup(NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy) {
        this.naturalIdCacheAccessStrategy = naturalIdCacheAccessStrategy;
        this.cacheLock = naturalIdCacheAccessStrategy.lockRegion();
        naturalIdCacheAccessStrategy.removeAll();
    }

    private void release() {
        naturalIdCacheAccessStrategy.unlockRegion( cacheLock );
    }
}

So, as you can see the whole data from the Region is evicted.

This only affects the second-level cache. The first level cache (a.k.a. Session) is not cleared every time you run a native query, because that would detach all your current “attached entities”, having unexpected consequences in entity state expectations. But before every query (HQL or native) the session is flushed so the DB and the session are in sync prior to executing the query, hence the 1st level cache is consistent before issuing a new select.

A whole region would get invalidated, not the whole second-level cache. An entity defines a cache region, so updating a specific entity table would only remove all the entities that belong to that particular table(s) that were affected by the native query.

But overriding the query-space definition associated with a native query is a way to customize Hibernate not to clear the cache region as it would do using the default implementation.

Categories
discuss

Setting the background color of ListView items on Button click

I have a FragmentActivity that can contain as many ListFragments as a user wants. The ListFragments are laid out side-by-side (upon choosing an option in the ActionBar) inside a HorizontalScrollView. Each ListFragment item contains a TextView and a Button. Clicking on the Button changes the background color of the Button’s ViewParent – a LinearLayout containing the Button and the TextView.

Now, clicking the Button in each ListFragment changes the background color of its corresponding list item, however upon scrolling buttons in list items that were not clicked also have their background color changed. This behavior is unexpected as only the items that were clicked are required to have their background color changed by a corresponding click on its Button.

The data for the ListFragment comes from a custom SimpleAdapter that overrides the getView(int position, View convertView, ViewGroup parent) method where I attach a setOnClickListener to a Button, which changes the background color of its ViewParent when clicked.

I have spent many hours on this issue however I am unable to arrive at a solution. An explanation that helps understand the root cause of this behaviour would be really useful. Also any guidance to help set the background color of just one item when clicked is welcome.

Here is the code for my custom Adapter MyCustomAdapter that extends SimpleAdapter:

package com.example.androidlistfragmenttest;

import java.util.List;
import java.util.Map;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.SimpleAdapter;

public class MyAdapter extends SimpleAdapter{

Context context;

public MyAdapter(Context context, List<? extends Map<String, ?>> data,
        int resource, String[] from, int[] to) {
    super(context, data, resource, from, to);

    this.context = context;
}

@Override
public boolean areAllItemsEnabled() {
    return false;
}

@Override
public boolean isEnabled(int position) {
   return false;
}

@Override
public View getView(int position, View convertView, ViewGroup parent){

    View view = convertView;
    if(view == null){

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.fragment_layout, null);
        Button button = (Button) view.findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Log.v("GOJIRA","ATOMIC BREATH");
                // Changes parent view's background color
                View parent = (View) v.getParent();
                parent.setBackgroundColor(Color.GREEN);
            }   
        });

    }
    return view;
}


}

And the ListFragment:

package com.example.androidlistfragmenttest;

import java.util.ArrayList;
import java.util.HashMap;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragment extends ListFragment {

private ArrayList<HashMap<String,String>> arraylist;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment

    View view = inflater.inflate(R.layout.fragment_layout, container, false);
    return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState){

    super.onActivityCreated(savedInstanceState);
    arraylist = dataGenerator();
    MyAdapter adapter = new MyAdapter(getActivity().getApplicationContext(), arraylist, R.layout.fragment_layout,new String[]{"KEY"},new int[]{R.id.text_id});
    setListAdapter(adapter);

}
/*
 * Method to populate an adapter's data list.
 */
public ArrayList<HashMap<String,String>> dataGenerator(){

    HashMap<String,String> hashMap1 = new HashMap<String,String>();
    hashMap1.put("KEY", "A");

    HashMap<String,String> hashMap2 = new HashMap<String,String>();
    hashMap2.put("KEY", "B");

    HashMap<String,String> hashMap3 = new HashMap<String,String>();
    hashMap3.put("KEY", "C");

    HashMap<String,String> hashMap4 = new HashMap<String,String>();
    hashMap4.put("KEY", "D");

    HashMap<String,String> hashMap5 = new HashMap<String,String>();
    hashMap5.put("KEY", "E");

    ArrayList<HashMap<String,String>> arraylist = new ArrayList<HashMap<String,String>>();
    arraylist.add(hashMap1);
    arraylist.add(hashMap2);
    arraylist.add(hashMap3);
    arraylist.add(hashMap4);
    arraylist.add(hashMap5);


    return arraylist;
}

}

As well as the ListActivity:

package com.example.androidlistfragmenttest;

import java.util.Stack;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; 
import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends FragmentActivity {


private Stack<String> tagStack;
private Integer last_tag_number;

public MainActivity(){

    last_tag_number = new Integer("0");
    tagStack = new Stack<String>();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

    case R.id.add_fragment:
        addColumn();
        return true;


    case R.id.remove_column:
        removeColumn();
        return true;


    case android.R.id.home:
        // This ID represents the Home or Up button. In the case of this
        // activity, the Up button is shown. Use NavUtils to allow users
        // to navigate up one level in the application structure. For
        // more details, see the Navigation pattern on Android Design:
        //
        // http://developer.android.com/design/patterns/navigation.html#up-vs-back
        //
        NavUtils.navigateUpFromSameTask(this);
        return true;

    }
    return super.onOptionsItemSelected(item);
}

/*
 * This function adds a column pane to the screen
 *  
 */
public void addColumn(){

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    MyFragment fragment = new MyFragment();
    fragmentTransaction.add(R.id.fragment_activity, fragment,tagGenerator());
    fragmentTransaction.commit();

}

/*This function removes a column pane from the screen
 * 
 * 
 */

public void removeColumn(){

    if(tagStack.size() != 0){
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = fragmentManager.findFragmentByTag(tagStack.pop());
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.remove(fragment);
        fragmentTransaction.commit();
    }
}

/*
 * This function generates tags for each fragment that is displayed on the screen
 * The tags pose as unique identifiers for each fragment
 */
public String tagGenerator(){

    Integer tag_number; 

    if(last_tag_number.intValue() == 0){
        tag_number = last_tag_number;   
        int temp = last_tag_number.intValue();
        temp+=1;
        last_tag_number = Integer.valueOf(temp);
    }
    else{
        tag_number = new Integer(last_tag_number.intValue());
        int temp = last_tag_number.intValue();
        temp+=1;
        last_tag_number = Integer.valueOf(temp);
    }
    String tag = tag_number.toString();
    tagStack.push(tag);

    return tag;
}

}

And finally the layouts. For the ListFragment:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dp"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:layout_weight="1"
    android:layout_margin="5dp" >

   <ListView android:id="@id/android:list"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
   /> 

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/label" 
        android:layout_gravity="start"
    />

    <TextView 
        android:id="@+id/text_id"
        android:layout_width="0dp"
        android:layout_height="wrap_content" 
        android:layout_weight="1"
        android:layout_gravity="end"
    />

     <Button
         android:id="@+id/button"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:text="@string/button"
         android:layout_margin="2dp"
         android:layout_marginLeft="2dp"
         android:layout_marginRight="2dp"
         android:clickable="true"

      />


</LinearLayout>   

And for the FragmentActivity:

<?xml version="1.0" encoding="utf-8"?>

<HorizontalScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<LinearLayout  
     android:id="@+id/fragment_activity"
     android:layout_width="fill_parent" 
     android:layout_height = "fill_parent"
     android:orientation = "horizontal"
     android:gravity="center"       
 > 

</LinearLayout> 
</HorizontalScrollView>

Answer

Answering my question.

The devil is in the detail. convertView is the View that is recycled. Any code within the if(view == null) block of the overridden getView(int position, View convertView, ViewGroup parent) will be recycled as well. Moving the Button and its associated listener outside this block will provide access to absolute list item positions instead of recycled positions. These positions can then be stored and the corresponding list item background color / state can be maintained. Here is my custom adapter’s getView method:

Edit: This solution is based on @matiash’s suggestion who has also provided an answer to this question.

@Override
public View getView(int position, View convertView, ViewGroup parent){

    //convertView is the recycled view.

    View view = convertView;
    final int pos = position;

    /*  Views are recycled within this block. 
     *  Only recycled relative list item positions accessible here.
     */

    if(view == null){

        final View viewClick = view;

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.fragment_layout, null);  

    }

   /*   
    *  Button moved out of if(view == null) block. 
    *  Views are not recycled here. Absolute list item positions accessible.
    *  Absolute list positions saved in an ArrayList (coloredItems).
    */  

    Button button = (Button) view.findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener(){


        @Override
        public void onClick(View v) {

            //This is always a refreshed position and never an absolute list item position.
            Log.d("CLICKED POSITION",Integer.valueOf(pos).toString());
            View parent = (View) v.getParent();

            parent.setBackgroundColor(Color.GREEN);
            coloredItems.add(Integer.valueOf(pos));             
        }
    });

     /*
      * This ensures that only list item positions saved 
      * in the ArrayList 'coloredItems' have a green background.
      * All other list items have a transparent background.
      */

    if(coloredItems.contains(Integer.valueOf(position)))
        view.setBackgroundColor(Color.GREEN);
    else
        view.setBackgroundColor(Color.TRANSPARENT);

    return view;
}
Categories
discuss

Magnifying glass that follows cursor for canvas

I’m working on a t-shirt designer for a client of mine and I made it using html5 canvas. The shirt designer is now finished but he requested I add a magnifying glass (something like this: http://mlens.musings.it/). I’ve found a lot of similar scripts out there, however, they all seem to have one thing in common they use a small and a large image. Using canvas, however, I have a different scenario and have been stumped on how I can add a magnifying glass to magnify where ever the cursor is on canvas.

Are there any scripts that exist that can get this done? or what other options would I have?

Answer

Let’s just draw the canvas to another canvas but scaled.

fiddle example

context.drawImage allows us to specify how much of the origin canvas we want to get and how big to draw it on the destination canvas. So to do a times 2 zoom we just draw the origin canvas twice the size to the destination canvas.

var main = document.getElementById("main");
var zoom = document.getElementById("zoom");
var ctx = main.getContext("2d")
var zoomCtx = zoom.getContext("2d");
var img = new Image();
img.src = "http://astrobioloblog.files.wordpress.com/2011/10/duck-1.jpg"
img.onload = run;

function run(){
    ctx.drawImage(img,0,0);
}

main.addEventListener("mousemove", function(e){
    //console.log(e);
    zoomCtx.drawImage(main, e.x, e.y, 200, 100, 0,0, 400, 200);
    zoom.style.top = e.pageY + 10+ "px"
    zoom.style.left = e.pageX +10+ "px"
    zoom.style.display = "block";
});

main.addEventListener("mouseout", function(){
    zoom.style.display = "none";
});
Categories
discuss

Remove first occurrence of comma in a string

I am looking for a way to remove the first occurrence of a comma in a string, for example

"some text1, some tex2, some text3"

should return instead:

"some text1 some text2, some tex3"

So, the function should only look if there’s more than one comma, and if there is, it should remove the first occurrence. This could be probably solved with the regex but I don’t know how to write it, any ideas ?

Answer

This will do it:

if (str.match(/,.*,/)) { // Check if there are 2 commas
    str = str.replace(',', ''); // Remove the first one
}

When you use the replace method with a string rather than an RE, it just replaces the first match.

Categories
discuss

How can I force a Mongoose Save() call to be synchronous

I am writing a script in Node.js which needs to do the following:

  1. Open XML file
  2. For each node in file
  3. Do a mongodb lookup to try find object relating to this node
  4. if object not found, create it, otherwise manipulate the found object in some manner
  5. save the (possibly new) object back to the database.
  6. goto step 2

I have looked at this for some time and come to the conclusion that it is almost impossible to do this with asynchronous mongodb. The problems are multiple, but for example if you are dealing with 20,000 of these nodes then doing it async will hang the script. However doing them as a batch insert isn’t feasible either due to step 4 needing to look if the object already exists or not.

It would be possible to cobble something horrible together which caches the created objects and then saves them as something like step 7, except it would be difficult because there are multiple collections that the objects are going into, and you would need to try look up objects from the cache first, then the database, at step 4. If that is the solution then I will just write off Javascript as broken and write this in perl instead. So my question is this, for something so simple as the above sequence of actions, can I somehow force mongodb to be synchronous so that my script doesn’t turn into insanity? I want to be able to say document.save() (I’m using Mongoose by the way) and then have it not return until after it has actually saved.

Edit: Added code

This is called from a loop roughly 20000 times. I don’t care (within reason) how long it takes, but 200,000 async calls to save hangs the script so it can’t be that (it also uses over 1.5gig of ram at that point). If I cannot make hObj.save(); wait until the object is actually saved then I am going to need to write this in a more capable language.

    models('hs').findOne({name: r2.$.name}, function (err, h) {
    if (err) {
        console.log(err);
    } else {
        var resultObj = createResult(meeting, r1, r2);

        if (h == undefined) {

            var hObj = new models('hs')({
                name : r2.$.name,
                results : [resultObj],
                numResults : 1
            });

            hObj.save();
        } else {
            h.results.push(resultObj);
            h.numResults++;
            h.save();
        }
    }
});

Answer

From the async github page:

eachSeries(arr, iterator, callback)

The same as each, only iterator is applied to each item in arr in series. The next iterator is only called once the current one has completed. This means the iterator functions will complete in order.

So assuming you have your XML nodes in nodes

async.eachSeries(
  nodes,
  // This will be applied to every node in nodes
  function (node, callback) {
    models('hs').findOne({name: r2.$.name}, function (err, h) {
      if (err) {
        console.log(err);
      } else {
        // Async?
        var resultObj = createResult(meeting, r1, r2);

        if (h == undefined) {

          var hObj = new models('hs')({
            name : r2.$.name,
            results : [resultObj],
            numResults : 1
          });

          hObj.save(function (err, p) {
            // Callback will tell async that you are done
            callback();
          });
        } else {
          h.results.push(resultObj);
          h.numResults++;
          h.save(function (err, p) {
            // Callback will tell async that you are done
            callback();
          });
        }
      }
    });
  },
  // This will be executed when all nodes has been processed
  function (err) {
    console.log('done!');
  }
);
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..