Reading uncommitted generated IDs in Spring / JPA - spring

I am trying to retrieve the generated ID of a newly created Entity within a transaction, but when I try to read the ID value it is null. I assume this is because the transaction has not yet been committed and the Entity's ID has yet to be created.
I am using Spring MVC and transactions (using #Transactional on my service), and using JPA for the data layer. I'm not an expert in transaction management, so I'm not even sure if this is possible. This is example code being executing in the presentation layer (Spring portlet MVC):
Long parentId = getParentId();
Folder parentFolder = linksService.getItem(parentId, Folder.class);
Folder newFolder;
newFolder = new Folder();
newFolder.setName("new folder");
newFolder.setParent(parentFolder);
parentFolder.addItem(newItem);
linksService.saveItem(parentFolder); // this calls entityManager.merge(parentFolder)
// this returns null
String itemId = newFolder.getItemId();
EDIT:
Here are the entities. I am using Oracle db.
#Entity
#Table(name = "LINK_ITEM")
#DiscriminatorColumn(name = "ITEM_TYPE")
public abstract class Item {
/**
* The Id of this item
*/
#Id
#TableGenerator(name = "table_gen", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.TABLE,
generator = "table_gen")
#Column(name = "ITEM_ID")
private Long itemId;
/**
* The name of this item
*/
private String name;
/**
* the parent item of this item
*/
#ManyToOne
#JoinColumn(name="PARENT_ID")
private Item parent;
/**
* The user ID that owns this item
*/
private String owner;
/**
* #return Returns the itemId.
*/
public Long getItemId() {
return itemId;
}
/**
* #param itemId
* The itemId to set.
*/
public void setItemId(Long itemId) {
this.itemId = itemId;
}
/**
* #return Returns the name.
*/
public String getName() {
return name;
}
/**
* #param name
* The name to set.
*/
public void setName(String name) {
this.name = name;
}
/**
* #return Returns the owner.
*/
public String getOwner() {
return owner;
}
/**
* #param owner
* The owner to set.
*/
public void setOwner(String owner) {
this.owner = owner;
}
/**
* #return Returns the parent.
*/
public Item getParent() {
return parent;
}
/**
* #param parent
* The parent to set.
*/
public void setParent(Item parent) {
this.parent = parent;
}
/**
* Returns the depth of this object in the folder tree. 0 is the top folder,
* 1 is one level down, etc.
*
* #return Returns the depth.
*/
#Transient
public long getDepth() {
long i = 0;
for (Item item = this; item.getParent() != null; item = item
.getParent()) {
++i;
}
return i;
}
/**
* Changes the parent folder of this item and updates links / children
* appropriately.
*
* #param parentFolder
*/
public void updateParent(Folder parentFolder) {
removeFromParent();
parentFolder.addItem(this);
}
/**
* Removes this item from it's parent folder, if it has one.
*/
public void removeFromParent() {
if (getParent() != null) {
((Folder) getParent()).removeItem(this);
}
}
public void moveUp() {
if (getParent() == null) {
return;
}
Folder parent = (Folder) getParent();
List<Item> siblings = parent.getChildren();
int index = siblings.indexOf(this);
if (index > 0) {
Item previousItem = siblings.get(index - 1);
siblings.set(index, previousItem);
siblings.set(index - 1, this);
}
}
public void moveDown() {
if (getParent() == null) {
return;
}
Folder parent = (Folder) getParent();
List<Item> siblings = parent.getChildren();
int index = siblings.indexOf(this);
int numItems = siblings.size();
if ((numItems > 1) && (index < (numItems - 1))) {
Item nextItem = (Item) siblings.get(index + 1);
siblings.set(index, nextItem);
siblings.set(index + 1, this);
}
}
/**
* Returns the String representation of this Item.
*/
#Override
public String toString() {
return "itemId=" + this.getItemId() + "; name=" + this.getName()
+ "; owner=" + this.getOwner();
}
}
#Entity
#DiscriminatorValue("F")
public class Folder extends Item {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name="PARENT_ID", referencedColumnName="ITEM_ID")
private List<Item> children = new ArrayList<Item>();
#Transient
private String path;
#Transient
private boolean open;
#Transient
private Collection<Link> orderedLinks;
/**
* #return Returns the children.
*/
public List<Item> getChildren() {
return children;
}
/**
* #param children
* The children to set.
*/
public void setChildren(List<Item> children) {
this.children = children;
}
/**
* Changes the parent folder of this item and updates links / children
* appropriately.
*
* #param parentFolder
*/
public void updateParent(Folder parentFolder) {
super.updateParent(parentFolder);
// update the path since the parent folder has changed
updatePath();
}
/**
* #param newItem
*/
public void addItem(Item newItem) {
newItem.setParent(this);
getChildren().add(newItem);
}
/**
* #param item
*/
public void removeItem(Item item) {
getChildren().remove(item);
item.setParent(null);
}
/**
*
* #param items
*/
public void addItems(List<? extends Item> items) {
for (Item item : items)
addItem(item);
}
/**
*
* #param items
*/
public void removeItems(List<? extends Item> items) {
for (Item item : items)
removeItem(item);
}
/**
* Returns a list of Folder objects that are the subfolders of this folder.
* This folder is also included at the top of the list.
*
* #return
* #throws ServiceException
*/
#Transient
public List<Folder> getFolderList() {
List<Folder> folderList = new ArrayList<Folder>();
buildFolderList(folderList, null);
return folderList;
}
/**
* Returns a list of Folder objects that are the subfolders of this folder.
* This folder is also included at the top of the list. This method will
* exclude the "excludeFolder" and it's subfolders from the list.
*
* #param excludeFolder
* #return
*/
#Transient
public List<Folder> getFolderList(Folder excludeFolder) {
List<Folder> folderList = new ArrayList<Folder>();
buildFolderList(folderList, excludeFolder);
return folderList;
}
/**
* Returns a recursive list of the parent folder of this folder. Includes
* this folder in the list.
*
* #return
*/
#Transient
public List<Folder> getParentList() {
List<Folder> parentList = new ArrayList<Folder>();
Folder currentFolder = this;
parentList.add(currentFolder);
while (currentFolder.getParent() != null) {
currentFolder = (Folder) currentFolder.getParent();
parentList.add(currentFolder);
}
// reverse the ordering
Collections.reverse(parentList);
return parentList;
}
/**
* Private method called recursively to build a list of Folder's and
* subfolders of the parentFolder.
*
* #param folderList
* #param parentFolder
* #param excludeFolder
*/
private void buildFolderList(List<Folder> folderList, Folder excludeFolder) {
// Don't add the exclude folder to the list
if (excludeFolder != null && this.equals(excludeFolder)) {
return;
}
folderList.add(this);
if (!isFolderEmpty()) {
for (Item item : getChildren()) {
if (item instanceof Folder) {
((Folder) item).buildFolderList(folderList, excludeFolder);
}
}
}
}
/**
* #return Returns the folderEmpty.
*/
#Transient
public boolean isFolderEmpty() {
return children == null || children.isEmpty() || children.size() == 0;
}
/**
*
*/
private void updatePath() {
StringBuffer strBuffer = new StringBuffer("");
strBuffer.append(getName());
Item parent = getParent();
while (parent != null) {
strBuffer.insert(0, parent.getName() + " > ");
parent = parent.getParent();
}
this.path = strBuffer.toString();
}
/**
* #return Returns the path of this folder.
*/
public String getPath() {
if (this.path == null || this.path.length() == 0)
updatePath();
return this.path;
}
/**
* #param path
* The path to set.
*/
protected void setPath(String path) {
this.path = path;
}
public Item find(Long itemId) {
if (itemId.equals(getItemId()))
return this;
Item item = null;
List<Item> children = getChildren();
for (Item currentItem : children) {
if (currentItem.getItemId().equals(itemId)) {
item = currentItem;
break;
} else if (currentItem instanceof Folder) {
item = ((Folder) currentItem).find(itemId);
if (item != null)
break;
}
}
return item;
}
/**
* Returns the String representation of this Folder.
*/
#Override
public String toString() {
return super.toString() + "; path=" + this.getPath();
}
/**
*
* #return a list of Link objects that this Folder holds.
*/
#Transient
public List<Link> getLinks() {
List<Item> children = getChildren();
List<Link> links = new ArrayList<Link>(children.size()
- (children.size() / 2));
for (Item item : children) {
if (item instanceof Link) {
links.add((Link) item);
}
}
return links;
}
/**
* Returns the child Folders of this Folder and their child Folders, etc.
*
* #return
*/
#Transient
public List<Folder> getChildFolders() {
List<Folder> folderList = new ArrayList<Folder>();
buildFolderList(folderList, null);
folderList.remove(this);
return folderList;
}
public boolean isOpen() {
return open;
}
#Transient
public boolean isClosed() {
return !open;
}
public void setOpen(boolean open) {
this.open = open;
}
public Collection<Link> getOrderedLinks() {
return orderedLinks;
}
public void setOrderedLinks(Collection<Link> orderedLinks) {
this.orderedLinks = orderedLinks;
}
/*
* (non-Javadoc)
*
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || (obj.getClass() != this.getClass())) {
return false;
}
Folder folder = (Folder) obj;
return this.getItemId() == folder.getItemId();
}
/*
* (non-Javadoc)
*
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
int var = (int) (this.getItemId().longValue() ^ (this.getItemId()
.longValue() >>> 32));
int hash = 7;
hash = 31 * hash + var;
return hash;
}
}
#Entity
#DiscriminatorValue("L")
public class Link extends Item {
private String url;
public Link() {
}
public Link(String url) {
this.url = url;
}
/**
* #return Returns the url.
*/
public String getUrl() {
return url;
}
/**
* #param url
* The url to set.
*/
public void setUrl(String url) {
if (url != null && url.indexOf(":/") == -1)
url = "http://" + url;
this.url = url;
}
}
The Controller is calling the DAO, which calls entityManager.merge() (and I tried including entityManger.flush()). I also use OpenEntityInManagerInterceptor.

Since you are using TABLE sequencing the id will be assign on your persist() call. Are you detaching or serializing the objects? You may need to return the id assigned in persist to your client.

Try
entityManager.flush();
after saving the new Entity. This will force the JPA provider to synchronize your persistence context with the underlying database and as part of this any ids will be generated.

Related

what i should know to do this in android

i wanna ask you exactly about the action that when i click on the button, the result will be inserted directly and automatically into their "input id" ... how can i do it in the android??
Well, if you are not familiar with Android, then I will advise you to take some tutorials about Android basics and Java.
Apart from that, Android does provide geocoding functionality, you should have latitude and longitude to run the following code:
Geocoder geocoder;
List<Address> addresses;
geocoder = new Geocoder(this, Locale.getDefault());
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
String address = addresses.get(0).getAddressLine(0);
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();
If you don't have the latitude and longitude of the user and wanted to access it also from an android device, you can use the following process:
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Activity
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView textview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.geo_locations);
// check if GPS enabled
GPSTracker gpsTracker = new GPSTracker(this);
if (gpsTracker.getIsGPSTrackingEnabled())
{
String stringLatitude = String.valueOf(gpsTracker.latitude);
textview = (TextView)findViewById(R.id.fieldLatitude);
textview.setText(stringLatitude);
String stringLongitude = String.valueOf(gpsTracker.longitude);
textview = (TextView)findViewById(R.id.fieldLongitude);
textview.setText(stringLongitude);
String country = gpsTracker.getCountryName(this);
textview = (TextView)findViewById(R.id.fieldCountry);
textview.setText(country);
String city = gpsTracker.getLocality(this);
textview = (TextView)findViewById(R.id.fieldCity);
textview.setText(city);
String postalCode = gpsTracker.getPostalCode(this);
textview = (TextView)findViewById(R.id.fieldPostalCode);
textview.setText(postalCode);
String addressLine = gpsTracker.getAddressLine(this);
textview = (TextView)findViewById(R.id.fieldAddressLine);
textview.setText(addressLine);
}
else
{
// can't get location
// GPS or Network is not enabled
// Ask user to enable GPS/network in settings
gpsTracker.showSettingsAlert();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.varna_lab_geo_locations, menu);
return true;
}
}
GPS Tracker
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
/**
* Create this Class from tutorial :
* http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial
*
* For Geocoder read this : http://stackoverflow.com/questions/472313/android-reverse-geocoding-getfromlocation
*
*/
public class GPSTracker extends Service implements LocationListener {
// Get Class Name
private static String TAG = GPSTracker.class.getName();
private final Context mContext;
// flag for GPS Status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS Tracking is enabled
boolean isGPSTrackingEnabled = false;
Location location;
double latitude;
double longitude;
// How many Geocoder should return our GPSTracker
int geocoderMaxResults = 1;
// The minimum distance to change updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute
// Declaring a Location Manager
protected LocationManager locationManager;
// Store LocationManager.GPS_PROVIDER or LocationManager.NETWORK_PROVIDER information
private String provider_info;
public GPSTracker(Context context) {
this.mContext = context;
getLocation();
}
/**
* Try to get my current location by GPS or Network Provider
*/
public void getLocation() {
try {
locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
//getting GPS status
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
//getting network status
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
// Try to get location if you GPS Service is enabled
if (isGPSEnabled) {
this.isGPSTrackingEnabled = true;
Log.d(TAG, "Application use GPS Service");
/*
* This provider determines location using
* satellites. Depending on conditions, this provider may take a while to return
* a location fix.
*/
provider_info = LocationManager.GPS_PROVIDER;
} else if (isNetworkEnabled) { // Try to get location if you Network Service is enabled
this.isGPSTrackingEnabled = true;
Log.d(TAG, "Application use Network State to get GPS coordinates");
/*
* This provider determines location based on
* availability of cell tower and WiFi access points. Results are retrieved
* by means of a network lookup.
*/
provider_info = LocationManager.NETWORK_PROVIDER;
}
// Application can use GPS or Network Provider
if (!provider_info.isEmpty()) {
locationManager.requestLocationUpdates(
provider_info,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES,
this
);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(provider_info);
updateGPSCoordinates();
}
}
}
catch (Exception e)
{
//e.printStackTrace();
Log.e(TAG, "Impossible to connect to LocationManager", e);
}
}
/**
* Update GPSTracker latitude and longitude
*/
public void updateGPSCoordinates() {
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
/**
* GPSTracker latitude getter and setter
* #return latitude
*/
public double getLatitude() {
if (location != null) {
latitude = location.getLatitude();
}
return latitude;
}
/**
* GPSTracker longitude getter and setter
* #return
*/
public double getLongitude() {
if (location != null) {
longitude = location.getLongitude();
}
return longitude;
}
/**
* GPSTracker isGPSTrackingEnabled getter.
* Check GPS/wifi is enabled
*/
public boolean getIsGPSTrackingEnabled() {
return this.isGPSTrackingEnabled;
}
/**
* Stop using GPS listener
* Calling this method will stop using GPS in your app
*/
public void stopUsingGPS() {
if (locationManager != null) {
locationManager.removeUpdates(GPSTracker.this);
}
}
/**
* Function to show settings alert dialog
*/
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
//Setting Dialog Title
alertDialog.setTitle(R.string.GPSAlertDialogTitle);
//Setting Dialog Message
alertDialog.setMessage(R.string.GPSAlertDialogMessage);
//On Pressing Setting button
alertDialog.setPositiveButton(R.string.action_settings, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which)
{
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
//On pressing cancel button
alertDialog.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
}
});
alertDialog.show();
}
/**
* Get list of address by latitude and longitude
* #return null or List<Address>
*/
public List<Address> getGeocoderAddress(Context context) {
if (location != null) {
Geocoder geocoder = new Geocoder(context, Locale.ENGLISH);
try {
/**
* Geocoder.getFromLocation - Returns an array of Addresses
* that are known to describe the area immediately surrounding the given latitude and longitude.
*/
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, this.geocoderMaxResults);
return addresses;
} catch (IOException e) {
//e.printStackTrace();
Log.e(TAG, "Impossible to connect to Geocoder", e);
}
}
return null;
}
/**
* Try to get AddressLine
* #return null or addressLine
*/
public String getAddressLine(Context context) {
List<Address> addresses = getGeocoderAddress(context);
if (addresses != null && addresses.size() > 0) {
Address address = addresses.get(0);
String addressLine = address.getAddressLine(0);
return addressLine;
} else {
return null;
}
}
/**
* Try to get Locality
* #return null or locality
*/
public String getLocality(Context context) {
List<Address> addresses = getGeocoderAddress(context);
if (addresses != null && addresses.size() > 0) {
Address address = addresses.get(0);
String locality = address.getLocality();
return locality;
}
else {
return null;
}
}
/**
* Try to get Postal Code
* #return null or postalCode
*/
public String getPostalCode(Context context) {
List<Address> addresses = getGeocoderAddress(context);
if (addresses != null && addresses.size() > 0) {
Address address = addresses.get(0);
String postalCode = address.getPostalCode();
return postalCode;
} else {
return null;
}
}
/**
* Try to get CountryName
* #return null or postalCode
*/
public String getCountryName(Context context) {
List<Address> addresses = getGeocoderAddress(context);
if (addresses != null && addresses.size() > 0) {
Address address = addresses.get(0);
String countryName = address.getCountryName();
return countryName;
} else {
return null;
}
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Some tutorials:
https://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/
https://www.tutorialspoint.com/android/android_location_based_services.htm
https://www.rishabhsoft.com/blog/android-geocoding-and-reverse-geocoding
https://developers.google.com/maps/documentation/geocoding/start
https://www.tutorialspoint.com/android/android_location_based_services.htm

Set Request Not Working SNMP4j

I have searched everywhere but I haven't found the solution to my problem. I've tried all solutions involving changing the community name, certain different set classes and I still can't get the set to work for SNMP4j. The code executes fine and can be accessed from iReasoning MIB browser but will not change the value of the OID after the set executes. The SNMP classes and tester classes are below.
SNMPManager code:
public class SNMPManager {
Snmp snmp = null;
String address = null;
/**
* Constructor
*
* #param add
*/
public SNMPManager(String add) {
address = add;
}
public static void main(String[] args) throws IOException {
/**
* Port 161 is used for Read and Other operations Port 162 is used for the trap
* generation
*/
SNMPManager client = new SNMPManager("udp:127.0.0.1/161");
client.start();
/**
* OID - .1.3.6.1.2.1.1.1.0 => SysDec OID - .1.3.6.1.2.1.1.5.0 => SysName => MIB
* explorer will be usefull here, as discussed in previous article
*/
String sysDescr = client.getAsString(new OID(".1.3.6.1.2.1.1.1.0"));
System.out.println(sysDescr);
}
/**
* Start the Snmp session. If you forget the listen() method you will not get
* any answers because the communication is asynchronous and the listen() method
* listens for answers.
*
* #throws IOException
*/
public void start() throws IOException {
TransportMapping<?> transport = new DefaultUdpTransportMapping();
snmp = new Snmp(transport);
// Do not forget this line!
transport.listen();
}
/**
* Method which takes a single OID and returns the response from the agent as a
* String.
*
* #param oid
* #return
* #throws IOException
*/
public String getAsString(OID oid) throws IOException {
ResponseEvent event = get(new OID[] { oid });
return event.getResponse().get(0).getVariable().toString();
}
/**
* This method is capable of handling multiple OIDs
*
* #param oids
* #return
* #throws IOException
*/
public ResponseEvent get(OID oids[]) throws IOException {
PDU pdu = new PDU();
for (OID oid : oids) {
pdu.add(new VariableBinding(oid));
}
pdu.setType(PDU.GET);
ResponseEvent event = snmp.send(pdu, getTarget(), null);
if (event != null) {
return event;
}
throw new RuntimeException("GET timed out");
}
public ResponseEvent set(OID oid, String val) throws IOException {
PDU pdu = new PDU();
VariableBinding varBind = new VariableBinding(oid, new OctetString(val));
pdu.add(varBind);
pdu.setType(PDU.SET);
//pdu.setRequestID(new Integer32(1));
Target target = getTarget();
ResponseEvent event = snmp.set(pdu, target);
if (event != null) {
System.out.println("\nResponse:\nGot Snmp Set Response from Agent");
System.out.println("Snmp Set Request = " + event.getRequest().getVariableBindings());
PDU responsePDU = event.getResponse();
System.out.println("\nresponsePDU = " + responsePDU);
if (responsePDU != null) {
int errorStatus = responsePDU.getErrorStatus();
int errorIndex = responsePDU.getErrorIndex();
String errorStatusText = responsePDU.getErrorStatusText();
System.out.println("\nresponsePDU = " + responsePDU);
if (errorStatus == PDU.noError) {
System.out.println("Snmp Set Response = " + responsePDU.getVariableBindings());
} else {
System.out.println("errorStatus = " + responsePDU);
System.out.println("Error: Request Failed");
System.out.println("Error Status = " + errorStatus);
System.out.println("Error Index = " + errorIndex);
System.out.println("Error Status Text = " + errorStatusText);
}
}
return event;
}
throw new RuntimeException("SET timed out");
}
/**
* This method returns a Target, which contains information about where the data
* should be fetched and how.
*
* #return
*/
private Target getTarget() {
Address targetAddress = GenericAddress.parse(address);
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(targetAddress);
target.setRetries(2);
target.setTimeout(1500);
target.setVersion(SnmpConstants.version2c);
return target;
}
}
SNMPAgent code:
public class SNMPAgent extends BaseAgent {
private String address;
/**
*
* #param address
* #throws IOException
*/
public SNMPAgent(String address) throws IOException {
/**
* Creates a base agent with boot-counter, config file, and a CommandProcessor
* for processing SNMP requests. Parameters: "bootCounterFile" - a file with
* serialized boot-counter information (read/write). If the file does not exist
* it is created on shutdown of the agent. "configFile" - a file with serialized
* configuration information (read/write). If the file does not exist it is
* created on shutdown of the agent. "commandProcessor" - the CommandProcessor
* instance that handles the SNMP requests.
*/
super(new File("conf.agent"), new File("bootCounter.agent"),
new CommandProcessor(new OctetString(MPv3.createLocalEngineID())));
this.address = address;
}
/**
* Adds community to security name mappings needed for SNMPv1 and SNMPv2c.
*/
#Override
protected void addCommunities(SnmpCommunityMIB communityMIB) {
Variable[] com2sec = new Variable[] { new OctetString("public"), new OctetString("cpublic"), // security name
getAgent().getContextEngineID(), // local engine ID
new OctetString("public"), // default context name
new OctetString(), // transport tag
new Integer32(StorageType.nonVolatile), // storage type
new Integer32(RowStatus.active) // row status
};
MOTableRow<?> row = communityMIB.getSnmpCommunityEntry()
.createRow(new OctetString("public2public").toSubIndex(true), com2sec);
communityMIB.getSnmpCommunityEntry().addRow((SnmpCommunityEntryRow) row);
}
/**
* Adds initial notification targets and filters.
*/
#Override
protected void addNotificationTargets(SnmpTargetMIB arg0, SnmpNotificationMIB arg1) {
// TODO Auto-generated method stub
}
/**
* Adds all the necessary initial users to the USM.
*/
#Override
protected void addUsmUser(USM arg0) {
// TODO Auto-generated method stub
}
/**
* Adds initial VACM configuration.
*/
#Override
protected void addViews(VacmMIB vacm) {
vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c, new OctetString("cpublic"), new OctetString("v1v2group"),
StorageType.nonVolatile);
vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"), SecurityModel.SECURITY_MODEL_ANY,
SecurityLevel.NOAUTH_NOPRIV, MutableVACM.VACM_MATCH_EXACT, new OctetString("fullReadView"),
new OctetString("fullWriteView"), new OctetString("fullNotifyView"), StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"), new OctetString(),
VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
}
/**
* Unregister the basic MIB modules from the agent's MOServer.
*/
#Override
protected void unregisterManagedObjects() {
// TODO Auto-generated method stub
}
/**
* Register additional managed objects at the agent's server.
*/
#Override
protected void registerManagedObjects() {
// TODO Auto-generated method stub
}
#SuppressWarnings("unchecked")
protected void initTransportMappings() throws IOException {
transportMappings = new TransportMapping[1];
Address addr = GenericAddress.parse(address);
TransportMapping<?> tm = TransportMappings.getInstance().createTransportMapping(addr);
transportMappings[0] = tm;
}
/**
* Start method invokes some initialization methods needed to start the agent
*
* #throws IOException
*/
public void start() throws IOException {
init();
// This method reads some old config from a file and causes
// unexpected behavior.
// loadConfig(ImportModes.REPLACE_CREATE);
addShutdownHook();
getServer().addContext(new OctetString("public"));
finishInit();
run();
sendColdStartNotification();
}
/**
* Clients can register the MO they need
*/
public void registerManagedObject(ManagedObject mo) {
try {
server.register(mo, null);
} catch (DuplicateRegistrationException ex) {
throw new RuntimeException(ex);
}
}
public void unregisterManagedObject(MOGroup moGroup) {
moGroup.unregisterMOs(server, getContext(moGroup));
}
}
MOCreator code:
public class MOCreator {
public static MOScalar<Variable> createReadOnly(OID oid,Object value ){
return new MOScalar<Variable>(oid,
MOAccessImpl.ACCESS_READ_WRITE,
getVariable(value));
}
private static Variable getVariable(Object value) {
if(value instanceof String) {
return new OctetString((String)value);
}
throw new IllegalArgumentException("Unmanaged Type: " + value.getClass());
}
}
Tester class:
public class TestSNMPAgent {
String siteOIDNumber = "1";
String dataOIDNumber = "1";
String sensorOIDNumber = "1";
OID newOIDdata = new OID("1.3.6.1.4.1.1234.5." + siteOIDNumber + ".2." + dataOIDNumber + "." + sensorOIDNumber + ".0");
OID newOIDdata2 = new OID("1.3.6.1.4.1.1234.5.1.2.1.2.0");
OID newOIDdata3 = new OID("1.3.6.1.4.1.1234.5.1.2.1.3.0");
public static void main(String[] args) throws IOException {
TestSNMPAgent client = new TestSNMPAgent("udp:127.0.0.1/161");
client.init();
}
SNMPAgent agent = null;
/**
* This is the client which we have created earlier
*/
SNMPManager client = null;
String address = null;
/**
* Constructor
*
* #param add
*/
public TestSNMPAgent(String add) {
address = add;
}
/**
* Initiates the testing of the SNMP Agent.
* #throws IOException
*/
private void init() throws IOException {
/*agent = new SNMPAgent("172.21.1.103/2001");*/
agent = new SNMPAgent("172.21.1.103/2010");
agent.start();
// Since BaseAgent registers some MIBs by default we need to unregister
// one before we register our own sysDescr. Normally you would
// override that method and register the MIBs that you need
agent.unregisterManagedObject(agent.getSnmpv2MIB());
//agent.registerManagedObject(MOCreator.createReadOnly(sysDescr,"This Description is set By KGrewe"));
agent.registerManagedObject(MOCreator.createReadOnly(newOIDdata, "50"));
agent.registerManagedObject(MOCreator.createReadOnly(newOIDdata2, "NaN"));
agent.registerManagedObject(MOCreator.createReadOnly(newOIDdata3, "3"));
SNMPManager client1 = new SNMPManager("udp:127.21.1.103/2010");
client1.start();
client1.set(newOIDdata, "30");
//System.out.println(newOIDdata);
// Get back Value which is set
//System.out.println(client1.getAsString(newOIDdata));
while(true) {
}
}
}
Thanks for the help in advance.

Edit next row on tab

When i put all code in a SSCCE, it works as expected i.e first and third cells are editable. When tab on last column, takes to next row.
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Yunus
*/
public class CollectionForm extends Application{
private TableView table = new TableView();
private ObservableList<Collection> collectionList = FXCollections.<Collection>observableArrayList();
ListProperty<Collection> collectionListProperty = new SimpleListProperty<>();
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
// single cell selection mode
table.getSelectionModel().setCellSelectionEnabled(true);
//Create a custom cell factory so that cells can support editing.
Callback<TableColumn, TableCell> editableFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new EditableTableCell();
}
};
//A custom cell factory that creates cells that only accept numerical input.
Callback<TableColumn, TableCell> numericFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new NumericEditableTableCell();
}
};
Button b = createSaveCollectionBtn();
//Create columns
TableColumn colMNO = createMNOColumn(editableFactory);
TableColumn colName = createNameColumn(editableFactory);
TableColumn colQty = createQuantityColumn(numericFactory);
table.getColumns().addAll(colMNO, colName, colQty);
//Make the table editable
table.setEditable(true);
collectionListProperty.set(collectionList);
table.itemsProperty().bindBidirectional(collectionListProperty);
collectionList.add(new Collection());
collectionList.add(new Collection());
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.getChildren().addAll(b, table);
vbox.setPadding(new Insets(10, 0, 0, 10));
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
private void handleCollection(ActionEvent event){
for (Collection collection : collectionList) {
System.out.println("MNO: "+collection.getMno()+" Quantity: "+collection.getQuantity());
}
}
private Button createSaveCollectionBtn(){
Button btn = new Button("Save Collection");
btn.setId("btnSaveCollection");
btn.setOnAction(this::handleCollection);
return btn;
}
private TableColumn createQuantityColumn(Callback<TableColumn, TableCell> editableFactory) {
TableColumn colQty = new TableColumn("Quantity");
colQty.setMinWidth(25);
colQty.setId("colQty");
colQty.setCellValueFactory(new PropertyValueFactory("quantity"));
colQty.setCellFactory(editableFactory);
colQty.setOnEditCommit(new EventHandler<CellEditEvent<Collection, Long>>() {
#Override
public void handle(CellEditEvent<Collection, Long> t) {
((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow())).setQuantity(t.getNewValue());
}
});
return colQty;
}
private TableColumn createMNOColumn(Callback<TableColumn, TableCell> editableFactory) {
TableColumn colMno = new TableColumn("M/NO");
colMno.setMinWidth(25);
colMno.setId("colMNO");
colMno.setCellValueFactory(new PropertyValueFactory("mno"));
colMno.setCellFactory(editableFactory);
colMno.setOnEditCommit(new EventHandler<CellEditEvent<Collection, String>>() {
#Override
public void handle(CellEditEvent<Collection, String> t) {
((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow())).setMno(t.getNewValue());
}
});
return colMno;
}
private TableColumn createNameColumn(Callback<TableColumn, TableCell> editableFactory) {
TableColumn colName = new TableColumn("Name");
colName.setEditable(false);
colName.setMinWidth(100);
colName.setId("colName");
colName.setCellValueFactory(new PropertyValueFactory<Collection, String>("name"));
colName.setCellFactory(editableFactory);
//Modifying the firstName property
colName.setOnEditCommit(new EventHandler<CellEditEvent<Collection, String>>() {
#Override
public void handle(CellEditEvent<Collection, String> t) {
((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow())).setName(t.getNewValue());
}
});
return colName;
}
/**
*
* #author Graham Smith
*/
public class EditableTableCell<S extends Object, T extends String> extends AbstractEditableTableCell<S, T> {
public EditableTableCell() {
}
#Override
protected String getString() {
return getItem() == null ? "" : getItem().toString();
}
#Override
protected void commitHelper( boolean losingFocus ) {
commitEdit(((T) textField.getText()));
}
}
/**
*
* #author Graham Smith
*/
public class NumericEditableTableCell<S extends Object, T extends Number> extends AbstractEditableTableCell<S, T> {
private final NumberFormat format;
private boolean emptyZero;
private boolean completeParse;
/**
* Creates a new {#code NumericEditableTableCell} which treats empty strings as zero,
* will parse integers only and will fail if is can't parse the whole string.
*/
public NumericEditableTableCell() {
this( NumberFormat.getInstance(), true, true, true );
}
/**
* The integerOnly and completeParse settings have a complex relationship and care needs
* to be take to get the correct result.
* <ul>
* <li>If you want to accept only integers and you want to parse the whole string then
* set both integerOnly and completeParse to true. Strings such as 1.5 will be rejected
* as invalid. A string such as 1000 will be accepted as the number 1000.</li>
* <li>If you only want integers but don't care about parsing the whole string set
* integerOnly to true and completeParse to false. This will parse a string such as
* 1.5 and provide the number 1. The downside of this combination is that it will accept
* the string 1x and return the number 1 also.</li>
* <li>If you want to accept decimals and want to parse the whole string set integerOnly
* to false and completeParse to true. This will accept a string like 1.5 and return
* the number 1.5. A string such as 1.5x will be rejected.</li>
* <li>If you want to accept decimals and don't care about parsing the whole string set
* both integerOnly and completeParse to false. This will accept a string like 1.5x and
* return the number 1.5. A string like x1.5 will be rejected because ti doesn't start
* with a number. The downside of this combination is that a string like 1.5x3 will
* provide the number 1.5.</li>
* </ul>
*
* #param format the {#code NumberFormat} to use to format this cell.
* #param emptyZero if true an empty cell will be treated as zero.
* #param integerOnly if true only the integer part of the string is parsed.
* #param completeParse if true an exception will be thrown if the whole string given can't be parsed.
*/
public NumericEditableTableCell( NumberFormat format, boolean emptyZero, boolean integerOnly, boolean completeParse ) {
this.format = format;
this.emptyZero = emptyZero;
this.completeParse = completeParse;
format.setParseIntegerOnly(integerOnly);
}
#Override
protected String getString() {
return getItem() == null ? "" : format.format(getItem());
}
/**
* Parses the value of the text field and if matches the set format
* commits the edit otherwise it returns the cell to it's previous value.
*/
#Override
protected void commitHelper( boolean losingFocus ) {
if( textField == null ) {
return;
}
try {
String input = textField.getText();
if (input == null || input.length() == 0) {
if(emptyZero) {
setText( format.format(0) );
commitEdit( (T)new Integer( 0 ));
}
return;
}
int startIndex = 0;
ParsePosition position = new ParsePosition(startIndex);
Number parsedNumber = format.parse(input, position);
if (completeParse && position.getIndex() != input.length()) {
throw new ParseException("Failed to parse complete string: " + input, position.getIndex());
}
if (position.getIndex() == startIndex ) {
throw new ParseException("Failed to parse a number from the string: " + input, position.getIndex());
}
commitEdit( (T)parsedNumber );
} catch (ParseException ex) {
//Most of the time we don't mind if there is a parse exception as it
//indicates duff user data but in the case where we are losing focus
//it means the user has clicked away with bad data in the cell. In that
//situation we want to just cancel the editing and show them the old
//value.
if( losingFocus ) {
cancelEdit();
}
}
}
}
/**
* Provides the basis for an editable table cell using a text field. Sub-classes can provide formatters for display and a
* commitHelper to control when editing is committed.
*
* #author Graham Smith
*/
public abstract class AbstractEditableTableCell<S, T> extends TableCell<S, T> {
protected TextField textField;
public AbstractEditableTableCell() {
}
/**
* Any action attempting to commit an edit should call this method rather than commit the edit directly itself. This
* method will perform any validation and conversion required on the value. For text values that normally means this
* method just commits the edit but for numeric values, for example, it may first parse the given input. <p> The only
* situation that needs to be treated specially is when the field is losing focus. If you user hits enter to commit the
* cell with bad data we can happily cancel the commit and force them to enter a real value. If they click away from the
* cell though we want to give them their old value back.
*
* #param losingFocus true if the reason for the call was because the field is losing focus.
*/
protected abstract void commitHelper(boolean losingFocus);
/**
* Provides the string representation of the value of this cell when the cell is not being edited.
*/
protected abstract String getString();
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.selectAll();
textField.requestFocus();
}
});
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
//Once the edit has been cancelled we no longer need the text field
//so we mark it for cleanup here. Note though that you have to handle
//this situation in the focus listener which gets fired at the end
//of the editing.
textField = null;
}
#Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitHelper(false);
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitHelper(false);
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
TablePosition focusedCellPosition = getTableView().getFocusModel().getFocusedCell();
if (nextColumn != null) {
//if( focusedCellPosition.getColumn() ){}focusedCellPosition.getTableColumn()
System.out.println("Column: "+focusedCellPosition.getColumn());
System.out.println("nextColumn.getId();: "+nextColumn.getId());
if( nextColumn.getId().equals("colMNO") ){
collectionList.add(new Collection());
getTableView().edit((getTableRow().getIndex())+1,getTableView().getColumns().get(0) );
getTableView().layout();
} else {
getTableView().edit(getTableRow().getIndex(), nextColumn);
}
}else{
getTableView().edit((getTableRow().getIndex())+1,getTableView().getColumns().get(0) );
}
}
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
//This focus listener fires at the end of cell editing when focus is lost
//and when enter is pressed (because that causes the text field to lose focus).
//The problem is that if enter is pressed then cancelEdit is called before this
//listener runs and therefore the text field has been cleaned up. If the
//text field is null we don't commit the edit. This has the useful side effect
//of stopping the double commit.
if (!newValue && textField != null) {
commitHelper(true);
}
}
});
}
/**
*
* #param forward true gets the column to the right, false the column to the left of the current column
* #return
*/
private TableColumn<S, ?> getNextColumn(boolean forward) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
for (TableColumn<S, ?> column : getTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
//There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
int currentIndex = columns.indexOf(getTableColumn());
int nextIndex = currentIndex;
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
return columns.get(nextIndex);
}
private List<TableColumn<S, ?>> getLeaves(TableColumn<S, ?> root) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
//We only want the leaves that are editable.
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TableColumn<S, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
public class Collection {
private int id;
private String mno;
private String name;
private float quantity;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMno() {
return mno;
}
public void setMno(String mno) {
this.mno = mno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getQuantity() {
return quantity;
}
public void setQuantity(float quantity) {
this.quantity = quantity;
}
}
}
The problem is when i take the same code to a controller and add this table programmatically, does not work as before: it jumps next line and go to third.
Before asking the TableView to edit the cell it's important to make sure that it has focus, that the cell in question is in view, and that the view layout is up to date. This is probably because of the way TableView uses virtual cells.
Add these three lines before any call to TableView#edit:
getTableView().requestFocus();
getTableView().scrollTo(rowToEdit);
getTableView().layout();
// getTableView().edit goes here.
This solved this problem for me.

Quartz doesn't recognize schema job_scheduling_data_2_0.xsd present in quartz jar file

I am getting below exception on server startup.
I am using quartz 2.2.21 with spring 3.2.
I have enabled quartz plugin (org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin).
Please find below the start tag of our XML file:
During server startup we are getting below log information and stacktrace:
Error Message:
Unable to load local schema packaged in quartz distribution jar. Utilizing schema online at http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd
Exception:
Caused by: org.xml.sax.SAXParseException; systemId: file:///quartz_job_data.xml; lineNumber: 5; columnNumber: 104;
schema_reference.4: Failed to read schema document 'http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
I have the same problem. I'm using the 7.1.1 of Jboss and the problem appears when you don't have connection to the internet. This is easy as putting a fake address that's unreachable in hosts.
I tried to force to local copy but it does not work.
What I finally did is to partially overwrite the functionality until this is fixed. Watch: https://jira.spring.io/browse/SPR-13706
public class CustomXMLSchedulingDataProcessor extends org.quartz.xml.XMLSchedulingDataProcessor {
public static final String QUARTZ_XSD_PATH_IN_JAR_CLASSPATH = "classpath:org/quartz/xml/job_scheduling_data_2_0.xsd";
public CustomXMLSchedulingDataProcessor(ClassLoadHelper clh) throws ParserConfigurationException {
super(clh);
}
#Override
protected Object resolveSchemaSource() {
InputSource inputSource;
InputStream is = null;
try {
is = classLoadHelper.getResourceAsStream(QUARTZ_XSD_PATH_IN_JAR_CLASSPATH);
} finally {
if (is != null) {
inputSource = new InputSource(is);
inputSource.setSystemId(QUARTZ_SCHEMA_WEB_URL);
}
else {
return QUARTZ_SCHEMA_WEB_URL;
}
}
return inputSource;
}
}
And I did a new plugin XMLSchedulingDataProcessorPlugin overwritting just the instanciation of above class.
public class XMLSchedulingDataProcessorPlugin
extends SchedulerPluginWithUserTransactionSupport
implements FileScanListener {
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Data members.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
private static final int MAX_JOB_TRIGGER_NAME_LEN = 80;
private static final String JOB_INITIALIZATION_PLUGIN_NAME = "JobSchedulingDataLoaderPlugin";
private static final String FILE_NAME_DELIMITERS = ",";
private boolean failOnFileNotFound = true;
private String fileNames = CustomXMLSchedulingDataProcessor.QUARTZ_XML_DEFAULT_FILE_NAME;
// Populated by initialization
private Map<String, JobFile> jobFiles = new LinkedHashMap<String, JobFile>();
private long scanInterval = 0;
boolean started = false;
protected ClassLoadHelper classLoadHelper = null;
private Set<String> jobTriggerNameSet = new HashSet<String>();
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Constructors.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
public XMLSchedulingDataProcessorPlugin() {
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* Comma separated list of file names (with paths) to the XML files that should be read.
*/
public String getFileNames() {
return fileNames;
}
/**
* The file name (and path) to the XML file that should be read.
*/
public void setFileNames(String fileNames) {
this.fileNames = fileNames;
}
/**
* The interval (in seconds) at which to scan for changes to the file.
* If the file has been changed, it is re-loaded and parsed. The default
* value for the interval is 0, which disables scanning.
*
* #return Returns the scanInterval.
*/
public long getScanInterval() {
return scanInterval / 1000;
}
/**
* The interval (in seconds) at which to scan for changes to the file.
* If the file has been changed, it is re-loaded and parsed. The default
* value for the interval is 0, which disables scanning.
*
* #param scanInterval The scanInterval to set.
*/
public void setScanInterval(long scanInterval) {
this.scanInterval = scanInterval * 1000;
}
/**
* Whether or not initialization of the plugin should fail (throw an
* exception) if the file cannot be found. Default is <code>true</code>.
*/
public boolean isFailOnFileNotFound() {
return failOnFileNotFound;
}
/**
* Whether or not initialization of the plugin should fail (throw an
* exception) if the file cannot be found. Default is <code>true</code>.
*/
public void setFailOnFileNotFound(boolean failOnFileNotFound) {
this.failOnFileNotFound = failOnFileNotFound;
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* SchedulerPlugin Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* <p>
* Called during creation of the <code>Scheduler</code> in order to give
* the <code>SchedulerPlugin</code> a chance to initialize.
* </p>
*
* #throws org.quartz.SchedulerConfigException
* if there is an error initializing.
*/
public void initialize(String name, final Scheduler scheduler, ClassLoadHelper schedulerFactoryClassLoadHelper)
throws SchedulerException {
super.initialize(name, scheduler);
this.classLoadHelper = schedulerFactoryClassLoadHelper;
getLog().info("Registering Quartz Job Initialization Plug-in.");
// Create JobFile objects
StringTokenizer stok = new StringTokenizer(fileNames, FILE_NAME_DELIMITERS);
while (stok.hasMoreTokens()) {
final String fileName = stok.nextToken();
final JobFile jobFile = new JobFile(fileName);
jobFiles.put(fileName, jobFile);
}
}
#Override
public void start(UserTransaction userTransaction) {
try {
if (jobFiles.isEmpty() == false) {
if (scanInterval > 0) {
getScheduler().getContext().put(JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName(), this);
}
Iterator<JobFile> iterator = jobFiles.values().iterator();
while (iterator.hasNext()) {
JobFile jobFile = iterator.next();
if (scanInterval > 0) {
String jobTriggerName = buildJobTriggerName(jobFile.getFileBasename());
TriggerKey tKey = new TriggerKey(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME);
// remove pre-existing job/trigger, if any
getScheduler().unscheduleJob(tKey);
JobDetail job = newJob().withIdentity(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME).ofType(FileScanJob.class)
.usingJobData(FileScanJob.FILE_NAME, jobFile.getFileName())
.usingJobData(FileScanJob.FILE_SCAN_LISTENER_NAME, JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName())
.build();
SimpleTrigger trig = newTrigger().withIdentity(tKey).withSchedule(
simpleSchedule().repeatForever().withIntervalInMilliseconds(scanInterval))
.forJob(job)
.build();
getScheduler().scheduleJob(job, trig);
getLog().debug("Scheduled file scan job for data file: {}, at interval: {}", jobFile.getFileName(), scanInterval);
}
processFile(jobFile);
}
}
} catch(SchedulerException se) {
getLog().error("Error starting background-task for watching jobs file.", se);
} finally {
started = true;
}
}
/**
* Helper method for generating unique job/trigger name for the
* file scanning jobs (one per FileJob). The unique names are saved
* in jobTriggerNameSet.
*/
private String buildJobTriggerName(
String fileBasename) {
// Name w/o collisions will be prefix + _ + filename (with '.' of filename replaced with '_')
// For example: JobInitializationPlugin_jobInitializer_myjobs_xml
String jobTriggerName = JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName() + '_' + fileBasename.replace('.', '_');
// If name is too long (DB column is 80 chars), then truncate to max length
if (jobTriggerName.length() > MAX_JOB_TRIGGER_NAME_LEN) {
jobTriggerName = jobTriggerName.substring(0, MAX_JOB_TRIGGER_NAME_LEN);
}
// Make sure this name is unique in case the same file name under different
// directories is being checked, or had a naming collision due to length truncation.
// If there is a conflict, keep incrementing a _# suffix on the name (being sure
// not to get too long), until we find a unique name.
int currentIndex = 1;
while (jobTriggerNameSet.add(jobTriggerName) == false) {
// If not our first time through, then strip off old numeric suffix
if (currentIndex > 1) {
jobTriggerName = jobTriggerName.substring(0, jobTriggerName.lastIndexOf('_'));
}
String numericSuffix = "_" + currentIndex++;
// If the numeric suffix would make the name too long, then make room for it.
if (jobTriggerName.length() > (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length())) {
jobTriggerName = jobTriggerName.substring(0, (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length()));
}
jobTriggerName += numericSuffix;
}
return jobTriggerName;
}
/**
* Overriden to ignore <em>wrapInUserTransaction</em> because shutdown()
* does not interact with the <code>Scheduler</code>.
*/
#Override
public void shutdown() {
// Since we have nothing to do, override base shutdown so don't
// get extranious UserTransactions.
}
private void processFile(JobFile jobFile) {
if (jobFile == null || !jobFile.getFileFound()) {
return;
}
try {
CustomXMLSchedulingDataProcessor processor =
new CustomXMLSchedulingDataProcessor(this.classLoadHelper);
processor.addJobGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);
processor.addTriggerGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);
processor.processFileAndScheduleJobs(
jobFile.getFileName(),
jobFile.getFileName(), // systemId
getScheduler());
} catch (Exception e) {
getLog().error("Error scheduling jobs: " + e.getMessage(), e);
}
}
public void processFile(String filePath) {
processFile((JobFile)jobFiles.get(filePath));
}
/**
* #see org.quartz.jobs.FileScanListener#fileUpdated(java.lang.String)
*/
public void fileUpdated(String fileName) {
if (started) {
processFile(fileName);
}
}
class JobFile {
private String fileName;
// These are set by initialize()
private String filePath;
private String fileBasename;
private boolean fileFound;
protected JobFile(String fileName) throws SchedulerException {
this.fileName = fileName;
initialize();
}
protected String getFileName() {
return fileName;
}
protected boolean getFileFound() {
return fileFound;
}
protected String getFilePath() {
return filePath;
}
protected String getFileBasename() {
return fileBasename;
}
private void initialize() throws SchedulerException {
InputStream f = null;
try {
String furl = null;
File file = new File(getFileName()); // files in filesystem
if (!file.exists()) {
URL url = classLoadHelper.getResource(getFileName());
if(url != null) {
try {
furl = URLDecoder.decode(url.getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
furl = url.getPath();
}
file = new File(furl);
try {
f = url.openStream();
} catch (IOException ignor) {
// Swallow the exception
}
}
} else {
try {
f = new java.io.FileInputStream(file);
}catch (FileNotFoundException e) {
// ignore
}
}
if (f == null) {
if (isFailOnFileNotFound()) {
throw new SchedulerException(
"File named '" + getFileName() + "' does not exist.");
} else {
getLog().warn("File named '" + getFileName() + "' does not exist.");
}
} else {
fileFound = true;
}
filePath = (furl != null) ? furl : file.getAbsolutePath();
fileBasename = file.getName();
} finally {
try {
if (f != null) {
f.close();
}
} catch (IOException ioe) {
getLog().warn("Error closing jobs file " + getFileName(), ioe);
}
}
}
}
}
That way you only have to use this plugin in your configuration and everything will work by default.
org.quartz.plugin.jobInitializer.class =
com.level2.quartz.processor.plugin.XMLSchedulingDataProcessorPlugin

Serializing a long string in Hadoop

I have a class which implements WritableComparable class in Hadoop. This class has two string variables, one short and one very long. I use writeChars to write these variables and readLine to read them but it seems like I get some sort of error. What is the best way to serialize such a long String in Hadoop?
I think you can use byteswritable to make it more efficient. Check the below custom key which has BytesWritable type as callId.
public class CustomMRKey implements WritableComparable<CustomMRKey> {
private BytesWritable callId;
private IntWritable mapperType;
/**
* #default constructor
*/
public CustomMRKey() {
set(new BytesWritable(), new IntWritable());
}
/**
* Constructor
*
* #param callId
* #param mapperType
*/
public CustomMRKey(BytesWritable callId, IntWritable mapperType) {
set(callId, mapperType);
}
/**
* sets the call id and mapper type
*
* #param callId
* #param mapperType
*/
public void set(BytesWritable callId, IntWritable mapperType) {
this.callId = callId;
this.mapperType = mapperType;
}
/**
* This method returns the callId
*
* #return callId
*/
public BytesWritable getCallId() {
return callId;
}
/**
* This method sets the callId given a callId
*
* #param callId
*/
public void setCallId(BytesWritable callId) {
this.callId = callId;
}
/**
* This method returns the mapper type
*
*
* #return
*/
public IntWritable getMapperType() {
return mapperType;
}
/**
* This method is set to store the mapper type
*
* #param mapperType
*/
public void setMapperType(IntWritable mapperType) {
this.mapperType = mapperType;
}
#Override
public void readFields(DataInput in) throws IOException {
callId.readFields(in);
mapperType.readFields(in);
}
#Override
public void write(DataOutput out) throws IOException {
callId.write(out);
mapperType.write(out);
}
#Override
public boolean equals(Object obj) {
if (obj instanceof CustomMRCdrKey) {
CustomMRCdrKey key = (CustomMRCdrKey) obj;
return callId.equals(key.callId)
&& mapperType.equals(key.mapperType);
}
return false;
}
#Override
public int compareTo(CustomMRCdrKey key) {
int cmp = callId.compareTo(key.getCallId());
if (cmp != 0) {
return cmp;
}
return mapperType.compareTo(key.getMapperType());
}
}
To use in say mapper code say you can generate the key of BytesWritable form using something as following :-
You can call as :
CustomMRKey customKey=new CustomMRKey(new BytesWritable(),new IntWritable());
customKey.setCallId(makeKey(value, this.resultKey));
customKey.setMapperType(this.mapTypeIndicator);
Then makeKey method is something like below :-
public BytesWritable makeKey(Text value, BytesWritable key) throws IOException {
try {
ByteArrayOutputStream byteKey = new ByteArrayOutputStream(Constants.MR_DEFAULT_KEY_SIZE);
for (String field : keyFields) {
byte[] bytes = value.getString(field).getBytes();
byteKey.write(bytes,0,bytes.length);
}
if(key==null){
return new BytesWritable(byteKey.toByteArray());
}else{
key.set(byteKey.toByteArray(), 0, byteKey.size());
return key;
}
} catch (Exception ex) {
throw new IOException("Could not generate key", ex);
}
}
Hope this may help.

Resources