What is the way of reading a specific sheet from an Excel file using spring-batch-excel?
Specifically, I want to parse different sheets within an Excel file in a different manner, using a org.springframework.batch.item.excel.poi.PoiItemReader.
I can't see how to do this with the PoiItemReader, in that is appears to read each sheet in the document. Is there a way to handle sheets differently in the row mapper perhaps? Is it possible without writing a custom POI reader?
No way with out writing custom reader
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.batch.extensions.excel.Sheet;
import org.springframework.lang.Nullable;
public class PoiSheet implements Sheet {
private final DataFormatter dataFormatter = new DataFormatter();
private final org.apache.poi.ss.usermodel.Sheet delegate;
private final int numberOfRows;
private final String name;
private FormulaEvaluator evaluator;
/**
* Constructor which takes the delegate sheet.
* #param delegate the apache POI sheet
*/
PoiSheet(final org.apache.poi.ss.usermodel.Sheet delegate) {
super();
this.delegate = delegate;
this.numberOfRows = this.delegate.getLastRowNum() + 1;
this.name = this.delegate.getSheetName();
}
/**
* {#inheritDoc}
*/
#Override
public int getNumberOfRows() {
return this.numberOfRows;
}
/**
* {#inheritDoc}
*/
#Override
public String getName() {
return this.name;
}
/**
* {#inheritDoc}
*/
#Override
#Nullable
public String[] getRow(final int rowNumber) {
final Row row = this.delegate.getRow(rowNumber);
return map(row);
}
#Nullable
private String[] map(Row row) {
if (row == null) {
return null;
}
final List<String> cells = new LinkedList<>();
final int numberOfColumns = row.getLastCellNum();
for (int i = 0; i < numberOfColumns; i++) {
Cell cell = row.getCell(i);
CellType cellType = cell.getCellType();
if (cellType == CellType.FORMULA) {
cells.add(this.dataFormatter.formatCellValue(cell, getFormulaEvaluator()));
}
else {
cells.add(this.dataFormatter.formatCellValue(cell));
}
}
return cells.toArray(new String[0]);
}
/**
* Lazy getter for the {#code FormulaEvaluator}. Takes some time to create an
* instance, so if not necessary don't create it.
* #return the {#code FormulaEvaluator}
*/
private FormulaEvaluator getFormulaEvaluator() {
if (this.evaluator == null) {
this.evaluator = this.delegate.getWorkbook().getCreationHelper().createFormulaEvaluator();
}
return this.evaluator;
}
#Override
public Iterator<String[]> iterator() {
return new Iterator<String[]>() {
private final Iterator<Row> delegateIter = PoiSheet.this.delegate.iterator();
#Override
public boolean hasNext() {
return this.delegateIter.hasNext();
}
#Override
public String[] next() {
return map(this.delegateIter.next());
}
};
}
}
Excel Reader
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.batch.extensions.excel.AbstractExcelItemReader;
import org.springframework.batch.extensions.excel.Sheet;
import org.springframework.core.io.Resource;
public class ExcelSheetItemReader <T> extends AbstractExcelItemReader<T> {
private Workbook workbook;
private InputStream inputStream;
private int sheetIndex = 0;
#Override
protected Sheet getSheet(final int sheet) {
return new PoiSheet(this.workbook.getSheetAt(sheetIndex));
}
#Override
protected int getNumberOfSheets() {
return 1;
}
#Override
protected void doClose() throws Exception {
super.doClose();
if (this.inputStream != null) {
this.inputStream.close();
this.inputStream = null;
}
if (this.workbook != null) {
this.workbook.close();
this.workbook = null;
}
}
/**
* Open the underlying file using the {#code WorkbookFactory}. Prefer {#code File}
* based access over an {#code InputStream}. Using a file will use fewer resources
* compared to an input stream. The latter will need to cache the whole sheet
* in-memory.
* #param resource the {#code Resource} pointing to the Excel file.
* #param password the password for opening the file
* #throws Exception is thrown for any errors.
*/
#Override
protected void openExcelFile(final Resource resource, String password) throws Exception {
try {
File file = resource.getFile();
this.workbook = WorkbookFactory.create(file, password, false);
}
catch (FileNotFoundException ex) {
this.inputStream = resource.getInputStream();
this.workbook = WorkbookFactory.create(this.inputStream, password);
}
this.workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
}
public int getSheetIndex() {
return sheetIndex;
}
public void setSheetIndex(int sheetIndex) {
this.sheetIndex = sheetIndex;
}
}
Another example can be found here
Related
I want rename the PowerPoint slide master by apache poi. In PowerPoint GUI we do View - Slide Master - then we right click the top most slide on left side and select Rename Master from context menu.
In a PowerPoint presentation the master is named such as it's theme. We can get all masters using XMLSlideShow.getSlideMasters. XSLFSlideMaster
extends XSLFSheet. So we can get the theme of each master using XSLFSheet.getTheme. Once we have the XSLFTheme there are getters and setters for the name.
Example:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xslf.usermodel.*;
public class XSLFRenameMasterTheme {
public static void main(String[] args) throws Exception {
XMLSlideShow slideshow = new XMLSlideShow(new FileInputStream("Presentation.pptx"));
for (XSLFSlideMaster master : slideshow.getSlideMasters()) {
XSLFTheme theme = master.getTheme();
String name = theme.getName();
System.out.println(name);
theme.setName(name + " renamed");
System.out.println(theme.getName());
}
FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.pptx");
slideshow.write(out);
out.close();
slideshow.close();
}
}
For HSLFSlideShow is seems there is no access to master names supported. One can get the HSLFSlideMasters but not the names of them.
So if one needs doing that nevertheless, then one must know about the internals of the binary *.ppt file system. This is documented in [MS-PPT]: PowerPoint (.ppt) Binary File Format. The sheet names are in a SlideNameAtom. With knowledge about the internals one can create a class for that kind of record. This can providing methods for get and set the name then.
Example:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordAtom;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
public class HSLFRenameMaster {
// method for get SlideNameAtom out of the master
private static SlideNameAtom getSlideNameAtom(HSLFSlideMaster master) throws Exception {
SlideNameAtom slideNameAtomRecord = null;
Record record = master.getSheetContainer().findFirstOfType(0x0FBA);
if (record != null) { // SlideNameAtom exists
// get present data
ByteArrayOutputStream out = new ByteArrayOutputStream();
record.writeOut(out);
out.flush();
byte[] data = out.toByteArray();
out.close();
// create new SlideNameAtom from data
slideNameAtomRecord = new SlideNameAtom(data);
// replace old record with new SlideNameAtom
master.getSheetContainer().addChildBefore(
slideNameAtomRecord,
record
);
master.getSheetContainer().removeChild(record);
}
return slideNameAtomRecord;
}
public static void main(String[] args) throws Exception {
HSLFSlideShow slideshow = new HSLFSlideShow(new FileInputStream("Presentation.ppt"));
for (HSLFSlideMaster master : slideshow.getSlideMasters()) {
SlideNameAtom slideNameAtomRecord = getSlideNameAtom(master);
if (slideNameAtomRecord != null) {
String name = slideNameAtomRecord.getName();
System.out.println(name);
slideNameAtomRecord.setName(name + " renamed");
System.out.println(slideNameAtomRecord.getName());
}
}
FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.ppt");
slideshow.write(out);
out.close();
slideshow.close();
}
//class SlideNameAtom
//having methods for manipulating the [SlideNameAtom](https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx)
private static class SlideNameAtom extends RecordAtom {
private byte[] data;
private String name;
public SlideNameAtom() {
this.name = "Office";
setName(name);
}
public SlideNameAtom(byte[] data) {
this.data = data;
this.name = getName();
}
public void setName(String name) {
this.name = name;
int length = 8;
length += StringUtil.getToUnicodeLE(name).length;
this.data = new byte[length];
data[0] = (byte)0x20; data[1] = (byte)0x00;
data[2] = (byte)0xBA; data[3] = (byte)0x0F; //MUST be 0x0fba = RT_CString (little endian)
LittleEndian.putInt(data, 4, StringUtil.getToUnicodeLE(name).length);
StringUtil.putUnicodeLE(name, data, 8);
}
public String getName() {
return StringUtil.getFromUnicodeLE(this.data, 8, (this.data.length-8)/2);
}
#Override
public void writeOut(OutputStream out) throws IOException {
out.write(data);
}
#Override
public long getRecordType() { return 0x0FBA; }
}
}
The question is whether renaming the master is worth that effort.
It took me way too long to set up a listener on one property of the objects in my Observablelist and add a listener to it.
ObservableList<Track> observableResult = FXCollections.observableArrayList((Track tr)-> new Observable[]{tr.selectedProperty()});
observableResult.addListener(new ListChangeListener<Track>() {
#Override
public void onChanged(Change<? extends Track> c) {
c.next();
for(Track k : c.getAddedSubList()){
System.out.println(k.getTrackName());
}
}
});
But I can't seem to be able to locate the actual object the change has been made to. The Change class only appears to support added and removed members, which don't get triggered by the actual changes inside them.
I have a workaround for this, just calling another method that would loop trough the entire ObservableArrayList and get for example, only the selected items, but that gets pretty expensive after I have a couple of thousand objects. Finding the source members that got changed would allow me to just push them to another array and save a bunch of overhead.
You can call getFrom() on the change to get the index of the changed item. I don't think there's a way to actually figure out which property changed (if you have more than one property listed in the extractor) or get the old value, but maybe this is enough.
If you need more, you could consider registering your own listeners with the list to track, which would be tricky but not impossible.
Here's an SSCCE demonstrating the getFrom() call:
import java.util.Random;
import java.util.stream.IntStream;
import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
public class ListChangeListenerTest {
public static void main(String[] args) {
ObservableList<Item> itemList = FXCollections.observableArrayList(item -> new Observable[]{item.valueProperty()});
itemList.addListener((Change<? extends Item> c) -> {
while (c.next()) {
if (c.wasUpdated()) {
int index = c.getFrom();
System.out.println("Updated item at "+index+" new value is "+itemList.get(index).getValue());
}
}
});
IntStream.rangeClosed(1, 1000).mapToObj(Item::new).forEach(itemList::add);
Random rng = new Random();
itemList.get(rng.nextInt(itemList.size())).setValue(rng.nextInt(10000));
}
public static class Item {
private final IntegerProperty value = new SimpleIntegerProperty();
public Item(int value) {
setValue(value);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
}
}
Here's a version that manages the listeners on the property manually. Note that
This doesn't use an extractor on the list
The property in the Item bean is constructed passing a reference to the bean that owns the property. This allows the listener on the property to get a reference to the Item (via a bit of ugly downcasting)
This gives a bit more flexibility; e.g. if you wanted to check modifications on multiple properties and perform different actions, this would allow this. As you can see, the listener can also access the old value.
import java.util.Random;
import java.util.stream.IntStream;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
public class ListChangeListenerTest {
public static void main(String[] args) {
ChangeListener<Number> valueListener = (obs, oldValue, newValue) -> {
Item item = (Item) ((Property<?>) obs).getBean();
System.out.println("Value for "+item+" changed from " + oldValue + " to "+newValue);
};
ObservableList<Item> itemList = FXCollections.observableArrayList();
itemList.addListener((Change<? extends Item> change) -> {
while (change.next()) {
if (change.wasAdded()) {
for (Item item : change.getAddedSubList()) {
item.valueProperty().addListener(valueListener);
}
}
if (change.wasRemoved()) {
for (Item item : change.getRemoved()) {
item.valueProperty().removeListener(valueListener);
}
}
}
});
IntStream.rangeClosed(1, 1000).mapToObj(Item::new).forEach(itemList::add);
Random rng = new Random();
itemList.get(rng.nextInt(itemList.size())).setValue(rng.nextInt(10000));
}
public static class Item {
private final IntegerProperty value = new SimpleIntegerProperty(this, "value");
private final String id ;
public Item(int value) {
id = "Item "+value ;
setValue(value);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
#Override
public String toString() {
return id ;
}
}
}
Finally, if you want to account for "bulk" updates, you need to implement ObservableList yourself. You can do this by subclassing ModifiableObservableListBase, and the basic idea is pretty straightforward. The implementation is made a bit tedious by having to create the Change object representing the update, but it's not too bad. Here's an example that allows updating a contiguous range:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ModifiableObservableListBase;
public class UpdatingObservableList<T> extends ModifiableObservableListBase<T> {
private final List<T> list ;
public UpdatingObservableList(List<T> list) {
this.list = list ;
}
public UpdatingObservableList() {
this(new ArrayList<>());
}
public void updateSublist(int start, int end, Consumer<T> updater) {
if (start < 0) throw new ArrayIndexOutOfBoundsException("Start ("+start+") cannot be < 0");
if (end < start) throw new IllegalArgumentException("End ("+end+") cannot be less than start ("+start+")");
if (end > size()) throw new ArrayIndexOutOfBoundsException("End ("+end+") cannot be greater than list size ("+size()+")");
for (T element : list.subList(start, end)) {
updater.accept(element);
}
fireChange(createUpdate(start, end));
}
#Override
public T get(int index) {
return list.get(index);
}
#Override
public int size() {
return list.size();
}
#Override
protected void doAdd(int index, T element) {
list.add(index, element);
}
#Override
protected T doSet(int index, T element) {
return list.set(index, element);
}
#Override
protected T doRemove(int index) {
return list.remove(index);
}
private Change<T> createUpdate(int start, int end) {
return new Change<T>(this) {
private boolean initialState = true ;
#Override
public boolean next() {
if (initialState) {
initialState = false ;
return true ;
}
return false ;
}
#Override
public void reset() {
initialState = true ;
}
#Override
public int getFrom() {
checkState();
return start ;
}
#Override
public int getTo() {
checkState();
return end ;
}
#Override
public List<T> getAddedSubList() {
checkState();
return Collections.emptyList();
}
#Override
public List<T> getRemoved() {
checkState();
return Collections.emptyList();
}
#Override
protected int[] getPermutation() {
checkState();
return new int[0];
}
#Override
public boolean wasAdded() {
checkState();
return false ;
}
#Override
public boolean wasRemoved() {
checkState();
return false ;
}
#Override
public boolean wasUpdated() {
return true ;
}
#Override
public boolean wasPermutated() {
checkState();
return false ;
}
#Override
public int getRemovedSize() {
checkState();
return 0 ;
}
#Override
public int getAddedSize() {
checkState();
return 0 ;
}
private void checkState() {
if (initialState) {
throw new IllegalStateException("Must call Change.next()");
}
}
};
}
}
and here's a version of the test class that uses this. Note that the update is performed via the list:
import java.util.Random;
import java.util.stream.IntStream;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener.Change;
public class ListChangeListenerTest {
public static void main(String[] args) {
UpdatingObservableList<Item> itemList = new UpdatingObservableList<Item>();
itemList.addListener((Change<? extends Item> change) -> {
while (change.next()) {
if (change.wasUpdated()) {
for (int i = change.getFrom() ; i < change.getTo() ; i++) {
System.out.println(itemList.get(i) + " updated - new value: "+itemList.get(i).getValue());
}
}
}
});
IntStream.rangeClosed(1, 1000).mapToObj(Item::new).forEach(itemList::add);
Random rng = new Random();
int start = rng.nextInt(itemList.size());
int end = Math.min(itemList.size(), start + 1 + rng.nextInt(15));
itemList.updateSublist(start, end, item -> item.setValue(rng.nextInt(10000)));
}
public static class Item {
private final IntegerProperty value = new SimpleIntegerProperty(this, "value");
private final String id ;
public Item(int value) {
id = "Item "+value ;
setValue(value);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
#Override
public String toString() {
return id ;
}
}
}
i need to read the contents of text file, line by line and display it on the Jtable, the table should be editable by users as needed, Any help Appreciated. I am new to Java. Thank You.
My Text File: File Name(people.txt)
COLUMN_NAME COLUMN_TYPE IS_NULLABLE COLUMN_KEY COLUMN_DEFAULT EXTRA
Names VARCHAR(500) NO
Address VARCHAR(500) NO
My Code So Far:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Vector;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class readtext {
static public void main(String[] arg){
JScrollPane scroll;
JTable table;
DefaultTableModel model;
String fname="people";
try
{
FileInputStream fstream = new FileInputStream("D:/joy/text/"+fname+".txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine,str = null;
//Read File Line By Line
String text = "";
Vector myVector = new Vector();
while ((strLine = br.readLine()) != null) //loop through each line
{
myVector.add(strLine );
// Print the content on the console
text +=(strLine+"\n"); // Store the text file in the string
}
in.close();//Close the input stream
int i=0;
String fline=myVector.elementAt(0).toString();
String[] sp=fline.split("\\s+");
for(String spt:sp){
System.out.println(spt);
//model = new DefaultTableModel(spt, ); // I dont know how to put the strings
into Jtable here
table = new JTable(){
public boolean isCellEditable(int row, int column){
return false;
}
};
int a=0;// for text box name
for(i=1;i<myVector.size();i++){
str=myVector.elementAt(i).toString();
String[] res =str.split("\\s+");
int k=0;
for(String st:res)
System.out.println(st);
k++;a++; }
} }
catch(Exception e)
{
e.printStackTrace();
}
}
}
Thank You.
File Content: (Each attribute is separated by a semicolon and each line is a record.)
Hello1;123
World1;234
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class FileToJTable {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
new FileToJTable().createUI();
}
};
EventQueue.invokeLater(r);
}
private void createUI() {
try {
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
JTable table = new JTable();
String readLine = null;
StudentTableModel tableModel = new StudentTableModel();
File file = new File(""/*Give your File Path here*/);
FileReader reader = new FileReader(file);
BufferedReader bufReader = new BufferedReader(reader);
List<Student> studentList = new ArrayList<Student>();
while((readLine = bufReader.readLine()) != null) {
String[] splitData = readLine.split(";");
Student student = new Student();
student.setName(splitData[0]);
student.setNumber(splitData[1]);
studentList.add(student);
}
tableModel.setList(studentList);
table.setModel(tableModel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.setTitle("File to JTable");
frame.pack();
frame.setVisible(true);
} catch(IOException ex) {}
}
class Student {
private String name;
private String number;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
class StudentTableModel extends AbstractTableModel {
private List<Student> list = new ArrayList<Student>();
private String[] columnNames = {"Name", "Number"};
public void setList(List<Student> list) {
this.list = list;
fireTableDataChanged();
}
#Override
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return list.size();
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return list.get(rowIndex).getName();
case 1:
return list.get(rowIndex).getNumber();
default:
return null;
}
}
}
}
Well i didnt read ur code...however i'm telling u one of the simplest way of doing this...hope this helps
Define a DefaultTableModel:
String columns[] = { //Column Names// };
JTable contactTable = new JTable();
DefaultTableModel tableModel;
// specify number of columns
tableModel = new DefaultTableModel(0,2);
tableModel.setColumnIdentifiers(columns);
contactTable.setModel(tableModel);
Reading from text file:
String line;
BufferedReader reader;
try{
reader = new BufferedReader(new FileReader(file));
while((line = reader.readLine()) != null)
{
tableModel.addRow(line.split(", "));
}
reader.close();
}
catch(IOException e){
JOptionPane.showMessageDialog(null, "Error");
e.printStackTrace();
}
Also, if you want to allow users to edit the data, then you need to set a TableCellEditor on the cells that you want people to edit. You probably also want to start using a TableModel instead of hard coding the data in the JTable itself.
See http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
My JAXB parser suddenly stopped working today. It was working for several weeks. I get the following message. I haven't changed this code for several weeks. Wondering if this set up is good.
EDIT 2: Please could somebody help me! I can't figure this out.
EDIT 1:
My acceptance tests running the same code below are working fine. I believe this is a
classloading issue. I am using the JAXB and StAX in the JDK. However, when I deploy to jboss 5.1, I get the error below. Using 1.6.0_26 (locally) and 1.6.0_30 (dev server). Still puzzling over a solution.
unexpected element (uri:"", local:"lineEquipmentRecord"). Expected
elements are
<{}switchType>,<{}leSwitchId>,<{}nodeAddress>,<{}leId>,<{}telephoneSuffix>,<{}leFormatCode>,<{}groupIdentifier>,<{}telephoneNpa>,<{}telephoneLine>,<{}telephoneNxx>
Here is my unmarshalling class:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class PartialUnmarshaller<T> {
XMLStreamReader reader;
Class<T> clazz;
Unmarshaller unmarshaller;
public PartialUnmarshaller(InputStream stream, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError, JAXBException {
this.clazz = clazz;
this.unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
#Override
public boolean handleEvent(ValidationEvent event) {
System.out.println(event.getMessage());
return true;
}
});
this.reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);
/* ignore headers */
skipElements(XMLStreamConstants.START_DOCUMENT);
/* ignore root element */
reader.nextTag();
/* if there's no tag, ignore root element's end */
skipElements(XMLStreamConstants.END_ELEMENT);
}
public T next() throws XMLStreamException, JAXBException {
if (!hasNext())
throw new NoSuchElementException();
T value = unmarshaller.unmarshal(reader, clazz).getValue();
skipElements(XMLStreamConstants.CHARACTERS, XMLStreamConstants.END_ELEMENT);
return value;
}
public boolean hasNext() throws XMLStreamException {
return reader.hasNext();
}
public void close() throws XMLStreamException {
reader.close();
}
private void skipElements(Integer... elements) throws XMLStreamException {
int eventType = reader.getEventType();
List<Integer> types = new ArrayList<Integer>(Arrays.asList(elements));
while (types.contains(eventType))
eventType = reader.next();
}
}
This class is used as follows:
List<MyClass> lenList = new ArrayList<MyClass>();
PartialUnmarshaller<MyClass> pu = new PartialUnmarshaller<MyClass>(
is, MyClass.class);
while (pu.hasNext()) {
lenList.add(pu.next());
}
The XML being unmarshalled:
<?xml version="1.0" encoding="UTF-8"?>
<lineEquipment>
<lineEquipmentRecord>
<telephoneNpa>333</telephoneNpa>
<telephoneNxx>333</telephoneNxx>
<telephoneLine>4444</telephoneLine>
<telephoneSuffix>1</telephoneSuffix>
<nodeAddress>xxxx</nodeAddress>
<groupIdentifier>LEN</groupIdentifier>
</lineEquipmentRecord>
<lineEquipmentRecord>
<telephoneNpa>111</telephoneNpa>
<telephoneNxx>111</telephoneNxx>
<telephoneLine>2222</telephoneLine>
<telephoneSuffix>0</telephoneSuffix>
<nodeAddress>xxxx</nodeAddress>
<groupIdentifier>LEN</groupIdentifier>
</lineEquipmentRecord>
</lineEquipment>
Finally, here is MyClass:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* This class is used as an envelope to hold Martens
* line equipment information.
* #author spgezf
*
*/
#XmlRootElement(name="lineEquipmentRecord")
public class MyClass {
private String telephoneNpa;
private String telephoneNxx;
private String telephoneLine;
private String telephoneSuffix;
private String nodeAddress;
private String groupIdentifier;
public MyClass(){
}
// Getters and Setters.
#XmlElement(name="telephoneNpa")
public String getTelephoneNpa() {
return telephoneNpa;
}
public void setTelephoneNpa(String telephoneNpa) {
this.telephoneNpa = telephoneNpa;
}
#XmlElement(name="telephoneNxx")
public String getTelephoneNxx() {
return telephoneNxx;
}
public void setTelephoneNxx(String telephoneNxx) {
this.telephoneNxx = telephoneNxx;
}
#XmlElement(name="telephoneLine")
public String getTelephoneLine() {
return telephoneLine;
}
public void setTelephoneLine(String telephoneLine) {
this.telephoneLine = telephoneLine;
}
#XmlElement(name="telephoneSuffix")
public String getTelephoneSuffix() {
return telephoneSuffix;
}
public void setTelephoneSuffix(String telephoneSuffix) {
this.telephoneSuffix = telephoneSuffix;
}
#XmlElement(name="nodeAddress")
public String getNodeAddress() {
return nodeAddress;
}
public void setNodeAddress(String nodeAddress) {
this.nodeAddress = nodeAddress;
}
#XmlElement(name="groupIdentifier")
public String getGroupIdentifier() {
return groupIdentifier;
}
public void setGroupIdentifier(String groupIdentifier) {
this.groupIdentifier = groupIdentifier;
}
}
Thanks, this is classloading issue I couldn't overcome so I abandoned JAXB.
Your PartialUnmarshaller code worked for me. Below is an alternate version that changes the skipElements method that may work better.
import java.io.InputStream;
import java.util.NoSuchElementException;
import javax.xml.bind.*;
import javax.xml.stream.*;
public class PartialUnmarshaller<T> {
XMLStreamReader reader;
Class<T> clazz;
Unmarshaller unmarshaller;
public PartialUnmarshaller(InputStream stream, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError, JAXBException {
this.clazz = clazz;
this.unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
#Override
public boolean handleEvent(ValidationEvent event) {
System.out.println(event.getMessage());
return true;
}
});
this.reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);
/* ignore headers */
skipElements();
/* ignore root element */
reader.nextTag();
/* if there's no tag, ignore root element's end */
skipElements();
}
public T next() throws XMLStreamException, JAXBException {
if (!hasNext())
throw new NoSuchElementException();
T value = unmarshaller.unmarshal(reader, clazz).getValue();
skipElements();
return value;
}
public boolean hasNext() throws XMLStreamException {
return reader.hasNext();
}
public void close() throws XMLStreamException {
reader.close();
}
private void skipElements() throws XMLStreamException {
while(reader.hasNext() && !reader.isStartElement()) {
reader.next();
}
}
}
I am trying to get my head around the JavaFX stuff...
My program is a WindowBuilder based Gui, and I want a JavaFX graph, and a JavaFX live video-feed displayed in my app.
How do I implement it in my code? I have tried this, but I couldn't get it runnning.
The data feed isnt the problem. I just need to view it inside my JFrame as small squares...
Confused now :(
Here is my code: (I am sorry that it is a tad long, but I blame the examplecode from JavaFX :p
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import java.awt.Canvas;
import java.awt.SystemColor;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import javax.swing.UIManager.*;
/**
* #author
*
*/
public class MyClientApp extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
protected static final String BufferedWriter = null;
JFrame frame;
private JTextField textFieldUsername;
/**
* Create the application.
*/
public MyClientApp(BufferedWriter serverDataOut, BufferedReader serverDataIn) {
initialize();
}
/**
* Initialize the contents of the frame.
*
* #param serverDataOut
*
*/
private void initialize() {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// Nimbus Theme not avaliable
}
frame = new JFrame();
frame.setResizable(false);
frame.setTitle("*********** My Program ***********");
frame.setBounds(320, 130, 730, 570);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
Canvas canvasTemp = new Canvas();
canvasTemp.setBackground(SystemColor.window);
canvasTemp.setBounds(6, 277, 380, 255);
frame.getContentPane().add(canvasTemp);
Canvas canvasLevel = new Canvas();
canvasLevel.setBackground(SystemColor.window);
canvasLevel.setBounds(6, 10, 380, 255);
frame.getContentPane().add(canvasLevel);
}
public JFrame frame() {
return frame;
}
}
And here is the main file to get it running for you guys... :
Client.java
import java.io.IOException;
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
MyClientApp window = new MyClientApp(null, null);
window.frame.setVisible(true);
}
}
The code I want to implement is:
AdvancedLineChartSample.java (from JavaFX)
/**
* Copyright (c) 2008, 2012 Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*/
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.util.Duration;
/**
* An advanced line chart with a variety of actions and settable properties.
*
* #see javafx.scene.chart.LineChart
* #see javafx.scene.chart.Chart
* #see javafx.scene.chart.NumberAxis
* #see javafx.scene.chart.XYChart
*/
public class AdvancedLineChartSample extends Application {
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
root.getChildren().add(createChart());
}
protected LineChart<Number, Number> createChart() {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number,Number> lc = new LineChart<Number,Number>(xAxis,yAxis);
// setup chart
lc.setTitle("Temp Chart");
xAxis.setLabel("tid");
yAxis.setLabel("temp");
// add starting data
XYChart.Series<Number,Number> series = new XYChart.Series<Number,Number>();
series.setName("Dataset 1");
series.getData().add(new XYChart.Data<Number,Number>(20d, 50d));
series.getData().add(new XYChart.Data<Number,Number>(40d, 80d));
series.getData().add(new XYChart.Data<Number,Number>(50d, 90d));
series.getData().add(new XYChart.Data<Number,Number>(70d, 30d));
series.getData().add(new XYChart.Data<Number,Number>(170d, 122d));
lc.getData().add(series);
return lc;
}
#Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) { launch(args);
}
}
and the StreamingMediaPlayer.java (from JavaFX):
/**
* Copyright (c) 2008, 2012 Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*/
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.scene.media.MediaView;
import javafx.util.Duration;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.animation.ParallelTransition;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
/**
* A media player with controls for play, pause, stop, seek, and volume. This media player is playing media via HTTP Live Streaming, also known as HLS.
*
* #see javafx.scene.media.MediaPlayer
* #see javafx.scene.media.Media
*/
public class StreamingMediaPlayer extends Application {
private static final String MEDIA_URL = "http://download.oracle.com/otndocs/products/javafx/JavaRap/prog_index.m3u8";
private MediaPlayer mediaPlayer;
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
mediaPlayer = new MediaPlayer(new Media(MEDIA_URL));
mediaPlayer.setAutoPlay(true);
PlayerPane playerPane = new PlayerPane(mediaPlayer);
playerPane.setMinSize(480, 360);
playerPane.setPrefSize(480, 360);
playerPane.setMaxSize(480, 360);
// getStylesheets().add("ensemble/samples/media/OverlayMediaPlayer.css");
root.getChildren().add(playerPane);
}
public void play() {
Status status = mediaPlayer.getStatus();
if (status == Status.UNKNOWN || status == Status.HALTED) {
return;
}
if (status == Status.PAUSED || status == Status.STOPPED || status == Status.READY) {
mediaPlayer.play();
}
}
#Override public void stop() {
mediaPlayer.stop();
}
static class PlayerPane extends BorderPane {
private MediaPlayer mp;
private MediaView mediaView;
private final boolean repeat = false;
private boolean stopRequested = false;
private boolean atEndOfMedia = false;
private Duration duration;
private Slider timeSlider;
private Label playTime;
private Slider volumeSlider;
private HBox mediaTopBar;
private HBox mediaBottomBar;
private ParallelTransition transition = null;
#Override protected void layoutChildren() {
if (mediaView != null && getBottom() != null) {
mediaView.setFitWidth(getWidth());
mediaView.setFitHeight(getHeight() - getBottom().prefHeight(-1));
}
super.layoutChildren();
if (mediaView != null) {
mediaView.setTranslateX((((Pane)getCenter()).getWidth() - mediaView.prefWidth(-1)) / 2);
mediaView.setTranslateY((((Pane)getCenter()).getHeight() - mediaView.prefHeight(-1)) / 2);
}
}
#Override protected double computeMinWidth(double height) {
return mediaBottomBar.prefWidth(-1);
}
#Override protected double computeMinHeight(double width) {
return 200;
}
#Override protected double computePrefWidth(double height) {
return Math.max(mp.getMedia().getWidth(), mediaBottomBar.prefWidth(height));
}
#Override protected double computePrefHeight(double width) {
return mp.getMedia().getHeight() + mediaBottomBar.prefHeight(width);
}
#Override protected double computeMaxWidth(double height) { return Double.MAX_VALUE; }
#Override protected double computeMaxHeight(double width) { return Double.MAX_VALUE; }
public PlayerPane(final MediaPlayer mp) {
this.mp = mp;
setId("player-pane");
mediaView = new MediaView(mp);
Pane mvPane = new Pane() { };
mvPane.setId("media-pane");
mvPane.getChildren().add(mediaView);
setCenter(mvPane);
mediaTopBar = HBoxBuilder.create()
.padding(new Insets(5, 10, 5, 10))
.alignment(Pos.CENTER)
.opacity(1)
.build();
BorderPane.setAlignment(mediaTopBar, Pos.CENTER);
mediaBottomBar = HBoxBuilder.create()
.padding(new Insets(5, 10, 5, 10))
.alignment(Pos.CENTER)
.opacity(1)
.build();
BorderPane.setAlignment(mediaBottomBar, Pos.CENTER);
mp.currentTimeProperty().addListener(new ChangeListener<Duration>() {
#Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
updateValues();
}
});
mp.setOnPlaying(new Runnable() {
public void run() {
if (stopRequested) {
mp.pause();
stopRequested = false;
}
}
});
mp.setOnReady(new Runnable() {
public void run() {
duration = mp.getMedia().getDuration();
updateValues();
}
});
mp.setOnEndOfMedia(new Runnable() {
public void run() {
if (!repeat) {
stopRequested = true;
atEndOfMedia = true;
}
}
});
mp.setCycleCount(repeat ? MediaPlayer.INDEFINITE : 1);
// Time label
Label timeLabel = LabelBuilder.create()
.text("Time")
.minWidth(Control.USE_PREF_SIZE)
.textFill(Color.WHITE)
.build();
mediaTopBar.getChildren().add(timeLabel);
// Time slider
timeSlider = SliderBuilder.create()
.id("media-slider")
.minWidth(240)
.maxWidth(Double.MAX_VALUE)
.build();
timeSlider.valueProperty().addListener(new InvalidationListener() {
public void invalidated(Observable ov) {
if (timeSlider.isValueChanging()) {
// multiply duration by percentage calculated by slider position
if (duration != null) {
mp.seek(duration.multiply(timeSlider.getValue() / 100.0));
}
updateValues();
}
}
});
HBox.setHgrow(timeSlider, Priority.ALWAYS);
mediaTopBar.getChildren().add(timeSlider);
// Play label
playTime = LabelBuilder.create()
.prefWidth(130)
.minWidth(50)
.textFill(Color.WHITE)
.build();
mediaTopBar.getChildren().add(playTime);
// Volume label
Label volumeLabel = LabelBuilder.create()
.text("Vol")
.textFill(Color.WHITE)
.minWidth(Control.USE_PREF_SIZE)
.build();
mediaTopBar.getChildren().add(volumeLabel);
// Volume slider
volumeSlider = SliderBuilder.create()
.id("media-slider")
.prefWidth(120)
.maxWidth(Region.USE_PREF_SIZE)
.minWidth(30)
.build();
volumeSlider.valueProperty().addListener(new InvalidationListener() {
public void invalidated(Observable ov) {
}
});
volumeSlider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (volumeSlider.isValueChanging()) {
mp.setVolume(volumeSlider.getValue() / 100.0);
}
}
});
mediaTopBar.getChildren().add(volumeSlider);
setTop(mediaTopBar);
final EventHandler<ActionEvent> backAction = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
mp.seek(Duration.ZERO);
}
};
final EventHandler<ActionEvent> stopAction = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
mp.stop();
}
};
final EventHandler<ActionEvent> playAction = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
mp.play();
}
};
final EventHandler<ActionEvent> pauseAction = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
mp.pause();
}
};
final EventHandler<ActionEvent> forwardAction = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
Duration currentTime = mp.getCurrentTime();
mp.seek(Duration.seconds(currentTime.toSeconds() + 5.0));
}
};
mediaBottomBar = HBoxBuilder.create()
.id("bottom")
.spacing(0)
.alignment(Pos.CENTER)
.children(
ButtonBuilder.create()
.id("back-button")
.text("Back")
.onAction(backAction)
.build(),
ButtonBuilder.create()
.id("stop-button")
.text("Stop")
.onAction(stopAction)
.build(),
ButtonBuilder.create()
.id("play-button")
.text("Play")
.onAction(playAction)
.build(),
ButtonBuilder.create()
.id("pause-button")
.text("Pause")
.onAction(pauseAction)
.build(),
ButtonBuilder.create()
.id("forward-button")
.text("Forward")
.onAction(forwardAction)
.build()
)
.build();
setBottom(mediaBottomBar);
}
protected void updateValues() {
if (playTime != null && timeSlider != null && volumeSlider != null && duration != null) {
Platform.runLater(new Runnable() {
public void run() {
Duration currentTime = mp.getCurrentTime();
playTime.setText(formatTime(currentTime, duration));
timeSlider.setDisable(duration.isUnknown());
if (!timeSlider.isDisabled() && duration. greaterThan(Duration.ZERO) && !timeSlider.isValueChanging()) {
timeSlider.setValue(currentTime.divide(duration).toMillis() * 100.0);
}
if (!volumeSlider.isValueChanging()) {
volumeSlider.setValue((int) Math.round(mp.getVolume() * 100));
}
}
});
}
}
private static String formatTime(Duration elapsed, Duration duration) {
int intElapsed = (int)Math.floor(elapsed.toSeconds());
int elapsedHours = intElapsed / (60 * 60);
if (elapsedHours > 0) {
intElapsed -= elapsedHours * 60 * 60;
}
int elapsedMinutes = intElapsed / 60;
int elapsedSeconds = intElapsed - elapsedHours * 60 * 60 - elapsedMinutes * 60;
if (duration.greaterThan(Duration.ZERO)) {
int intDuration = (int)Math.floor(duration.toSeconds());
int durationHours = intDuration / (60 * 60);
if (durationHours > 0) {
intDuration -= durationHours * 60 * 60;
}
int durationMinutes = intDuration / 60;
int durationSeconds = intDuration - durationHours * 60 * 60 - durationMinutes * 60;
if (durationHours > 0) {
return String.format("%d:%02d:%02d",
elapsedHours, elapsedMinutes, elapsedSeconds);
} else {
return String.format("%02d:%02d",
elapsedMinutes, elapsedSeconds);
}
} else {
if (elapsedHours > 0) {
return String.format("%d:%02d:%02d",
elapsedHours, elapsedMinutes, elapsedSeconds);
} else {
return String.format("%02d:%02d",
elapsedMinutes, elapsedSeconds);
}
}
}
}
#Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
play();
}
public static void main(String[] args) { launch(args);
}
}
I'm sorry about the long code. Its just the samplecode from JavaFX. You find it here, and here.
That should be quite easy to solve. Let me explain it with the chart example that you've shown.
Add an instance of JFXPanel to your JFrame. In your examples, all components are added to a Stage, which is the JavaFX class to represent a window. So you don't need it here. Instead, you add the components that you want to use to the JFXPanel. See also here (function initAndShowGUI) how to do it.
In the init function of the example, a Scene is created as well as the chart itself. What you have to do to let the chart be shown is not much more than that - create a Scene, fill it with content and pass it to the JFXPanel that you already created.
With a minimum effort you can make your chart example run: Make sure that AdvancedLineChartSample.java is in your build path and that the function createChart is somehow accessible from your JFrame. Then add the chart to your code with something similar to the following snippet.
Group root=new Group();
Scene scene=new Scene(root);
myJFXPanel.setScene(scene);
root.getChildren().add(createChart());
This is just a very quick and dirty solution to run your example without any beautiful code and also I didn't test it. But hopefully it gives you a basic understanding of what's going on to encourage further experiments. By my own experience I can tell you that from this step on, there's a lot of fun to come with JavaFX 2.