Apache POI: SXSSFWorkbook.dispose() does not exist - excel

I'm using apache's POI API to write XLSX files. Since I need to write big files, I'm using the Streaming API (SXSSF).
To do this, I'm following this guide. Note that by the end of the example there's a call to
wb.dispose
This wb instance refers to a SXSSFWorkbook instance. I'm using the same in my code but it complains about the dispose method not existing. I downloaded the source code and the method isn't there. However, going to their SVN and checking that class' code we can see the method there:
https://svn.apache.org/repos/asf/poi/trunk/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
I already tried to recompile their code but I get a lot of errors...

The Apache POI 3.8 (latest stable at the time) creates a temporary XML file for each sheet (when using SXSSF) but does not gives the option to delete these files. This fact makes this API not good to use because if I'm exporting 600MB of data then I'll have 2 files with 600MB and one of them will be in the temporary folder until it's deleted.
Digging into the code, we see that the class SXSSFSheet has an instance of SheetDataWriter. This last class is responsible to write and maintain the temporary file that is represented by the File instance. Accessing this object would allow to delete the file.
All these instances are private so, theoretically, you cannot access them. However, through reflection, we can access the File instance to delete this useful but annoying files!
The following to methods allow to do this. By calling the deleteSXSSFTempFiles, all temporary files of that workbook are deleted.
/**
* Returns a private attribute of a class
* #param containingClass The class that contains the private attribute to retrieve
* #param fieldToGet The name of the attribute to get
* #return The private attribute
* #throws NoSuchFieldException
* #throws IllegalAccessException
*/
public static Object getPrivateAttribute(Object containingClass, String fieldToGet) throws NoSuchFieldException, IllegalAccessException {
//get the field of the containingClass instance
Field declaredField = containingClass.getClass().getDeclaredField(fieldToGet);
//set it as accessible
declaredField.setAccessible(true);
//access it
Object get = declaredField.get(containingClass);
//return it!
return get;
}
/**
* Deletes all temporary files of the SXSSFWorkbook instance
* #param workbook
* #throws NoSuchFieldException
* #throws IllegalAccessException
*/
public static void deleteSXSSFTempFiles(SXSSFWorkbook workbook) throws NoSuchFieldException, IllegalAccessException {
int numberOfSheets = workbook.getNumberOfSheets();
//iterate through all sheets (each sheet as a temp file)
for (int i = 0; i < numberOfSheets; i++) {
Sheet sheetAt = workbook.getSheetAt(i);
//delete only if the sheet is written by stream
if (sheetAt instanceof SXSSFSheet) {
SheetDataWriter sdw = (SheetDataWriter) getPrivateAttribute(sheetAt, "_writer");
File f = (File) getPrivateAttribute(sdw, "_fd");
try {
f.delete();
} catch (Exception ex) {
//could not delete the file
}
}
}
}

As of 2012-12-03, POI 3.9 is available as a stable release. The dispose() method is available in SXSSFWorkbook in this release.
(Of course, this was not the case when the question was asked.)

Related

How to retrieve an InputStream from SmbRemoteFileTemplate?

I'm using spring integration for SMB to store and retrieve files from windows server.
In cases when I want to retrieve the file from the server I found the method "get" which receives a lamda function to handler the InputStream, but I need return this element and I wouldn't like to store in local and then return the InputStream.
Is there any alternative for this matter?
Thank you all.
My code is like this:
#Override
protected InputStream readMetadataFile(final String filename) throws FileNotFoundException {
final File inputFile = new File(filename);
if (this.smbRemoteFileTemplate.exists(filename)) {
this.smbRemoteFileTemplate.get(filename, in -> FileUtils.copyInputStreamToFile(in, inputFile));
return new FileInputStream(inputFile);
}
return null;
}
PS: does any mate with reputation greater than 1500 could create the tag "spring-integration-smb"? Thanks again.
The RemoteFileTemplate is based on the SessionFactory and there is an API like this:
/**
* Obtain a raw Session object. User must close the session when it is no longer
* needed.
* #return a session.
* #since 4.3
*/
Session<F> getSession();
That Session has this one for you:
/**
* Retrieve a remote file as a raw {#link InputStream}.
* #param source The path of the remote file.
* #return The raw inputStream.
* #throws IOException Any IOException.
* #since 3.0
*/
InputStream readRaw(String source) throws IOException;
Let's hope that this path is enough for your use-case!
Note: that you are responsible for closing this InputStream after using.

Android Studio - data moving within tabs/fragments

I am currently doing on a project that requires me to move my data between tabs/fragments.. Let's say the user clicks on the listView item, they will move to another tab, instead of staying in the same tab. May I know how can I achieve that? Can someone help to solve my query? Thank you!
You can trasnfer data between tabs by set and get Arguments,
Here is Example
FragmentTwo fragmentTwo = new FragmentTwo();
Bundle bundle = new Bundle();
bundle.putString("key1", "data1");
bundle.putString("key2", "data2");
bundle.putString("key3", "data3");
fragmentTwo.setArguments(bundle);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_container, fragmentTwo);
fragmentTransaction.commit();
There are 3 ways to do this
1) Use Interfaces -use interface to pass data objects. Meshy solution
Read more
public interface onDataCHange{
public void updateData(String data);
}
2) Use Activity Class - Store model object in activity class and set and get using activity Instance. Quick and Dirty solution
Read more
//Get
Object dataModel = (ContainerActivity) getActivity()).getData();
//Set
((ContainerActivity) getActivity()).setData(dataModel );
3) Clean architecture - Center repository hold model objects. View update model via Singleton Center repository object. Single copy of data flow between throughout the App.
Read more
#Singleton
public class UserDataRepository implements UserRepository {
private final UserDataStoreFactory userDataStoreFactory;
private final UserEntityDataMapper userEntityDataMapper;
/**
* Constructs a {#link UserRepository}.
*
* #param dataStoreFactory A factory to construct different data source implementations.
* #param userEntityDataMapper {#link UserEntityDataMapper}.
*/
#Inject
UserDataRepository(UserDataStoreFactory dataStoreFactory,
UserEntityDataMapper userEntityDataMapper) {
this.userDataStoreFactory = dataStoreFactory;
this.userEntityDataMapper = userEntityDataMapper;
}
#Override public Observable<List<User>> users() {
//we always get all users from the cloud
final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
return userDataStore.userEntityList().map(this.userEntityDataMapper::transform);
}
#Override public Observable<User> user(int userId) {
final UserDataStore userDataStore = this.userDataStoreFactory.create(userId);
return userDataStore.userEntityDetails(userId).map(this.userEntityDataMapper::transform);
}
}

SXSSFWorkbook with Custom temp file

SXSSFWorkbook does what I want, but I would like to use a different type of temp file then what is provided and seemingly baked into the implementation.
In SheetDataWriter
public File createTempFile() throws IOException {
return TempFile.createTempFile("poi-sxssf-sheet", ".xml");
}
So...I can extend this by making a MySheetDataWriter and Overriding the call to createTempFile. However, there is no way to for me to use MySheetDataWriter in the SXSSFWorkbook...if I try to extendt it then the package protected method...could not be overidden, because it is not visible.
from SXSSFWorkbook
SheetDataWriter createSheetDataWriter() throws IOException {
if(_compressTmpFiles) {
return new GZIPSheetDataWriter(_sharedStringSource);
}
return new SheetDataWriter(_sharedStringSource);
}
So the bottom line is that I can use the implementation almost exactly as is, but I need a different kind of Temp file...not even just a different directory to put it in, but a completely different implementation. Any ideas on how to do this?
Starting at version 3.11, the createTempFile method you mention (from class TempFile) uses a replaceable TempFileCreationStrategy that can be chosen with the setTempFileCreationStrategy method.
The following example extends the default strategy to log every temp file that is created, but you could change it to return a custom File instance.
TempFile.setTempFileCreationStrategy(new TempFile.DefaultTempFileCreationStrategy() {
#Override
public File createTempFile(String prefix, String suffix) throws IOException {
File f = super.createTempFile(prefix, suffix);
log.debug("Created temp file: " + f);
return f;
}
});

Using property files in Web Applications [duplicate]

This question already has answers here:
How to get properties file from /WEB-INF folder in JSF?
(3 answers)
Closed 7 years ago.
I'm developing a web application(this is my first time) and pretty confused about using property files. I don't know where to put the property files.
The problem is that i have put it under the WEB_INF folder. And when i test run it as a Java Application to check whether Database connections are working according to the properties in the property file it is working without any problem.
But when i run it in a Server as a Web Application it fails to load the properties file saying it could not find the file in the path specified. I tried using every possible path i could give and changing the file directories within the whole project. But I kept getting the same error.
Then i changed my class again from scratch thinking there's some kind of a bug withing my code where i load the properties file. And it seems that it could not find the file either when deployed as a Web App. But my test application works fine. Where do i put this file and how do i use it. I have read #BalusC's answer in this thread https://stackoverflow.com/a/2161583/2999358 but i have no idea why this happens. Can someone help me on this?
I'm using Tomcat 8, Eclipse IDE and building on JSF framework.
Class where i load my properties file
public class ConfigCache {
private static final File FILE = new File("./WebContent/WEB-INF/conf/config.properties");
private static final Properties PROPERTIES = new Properties();
public static final String JDBC_DRIVER = ConfigCache.getProperty("db.driverName");
public static final String DATABASE_URL = ConfigCache.getProperty("db.url");
public static final String DATABASE_USERNAME = ConfigCache.getProperty("db.user");
public static final String DATABASE_PASSWORD = ConfigCache.getProperty("db.pass");
public ConfigCache() {
}
public static String getProperty(String key) {
if (PROPERTIES.isEmpty()) {
loadProperties();
}
Object value;
return (value = PROPERTIES.get(key)) == null ? "" : value.toString();
}
private static void loadProperties() {
if (!FILE.exists()) {
throw new IllegalArgumentException("The 'config.properties' has not been found.");
}
try {
FileInputStream fis = null;
try {
fis = new FileInputStream(FILE);
PROPERTIES.load(fis);
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException exp) {
System.out.println("IOException #" + ConfigCache.class + " # loadProperties() : " + exp);
}
}
} catch (Exception exp) {
System.out.println("Exception #" + ConfigCache.class + " # loadProperties() : " + exp);
}
}
}
Folder Structure
Try With this.
put the property in src folder.
Your file is in the WEB-INF directory. This means it's part of the war and reachable as part of the class path. That's perfectly ok, since it makes it portable and independant of the web container installation (e.g. Tomcat).
You can load any file in the class path as a resource:
getClass().getResourceAsStream("/conf/config.properties")
This means you can write your code like this:
private static void loadProperties() {
InputStream is = getClass().getResourceAsStream("/conf/config.properties");
PROPERTIES.load(fis);
}
(Error handling omitted)
You can explode (unzip) your war/ear file and see the contents or folder structure of it and find why your code doesnt work. The reason is that the folder WebContent doesnt exist in your ear/war , but does exist only when run via eclipse. This is the reason why its always better to follow the solution provided in the link posted so that you can retrieve the porperty files from classpath. The below code fetches your property file in eclipse but not in the server.
private static final File FILE = new File("./WebContent/WEB-INF/conf/config.properties");
Contents of WAR file (from JournelDev), it contains WEB-INF directory but there would be no WebContent directory above it

VSTO Excel: Restore ListObject data source when reopening a file

I am working on an Excel 2010 template project. In my template I have many sheets with static ListObject controls in each of them. To initialize my ListObject, I bind a BindingList<MyCustomType> so it generates a column for each of my MyCustomType public properties. It is really handy because when the user some rows in the ListObject, it automatically fills up my BindingList instance. I added a button in the Excel ribbon so that the program can validate and commit these rows through an EDM. This is how I bind my data to the ListObject in the startup event handler of one of my Excel sheet.
public partial class MyCustomTypesSheet
{
private BindingList<MyCustomType> myCustomTypes;
private void OnStartup(object sender, System.EventArgs e)
{
ExcelTools.ListObject myCustomTypeTable = this.MyCustomTypeData;
BindingList<MyCustomType> customTypes = new BindingList<MyCustomType>();
myCustomTypeTable.SetDataBinding(customTypes);
}
// Implementation detail...
}
Now my issue is that it is very likely that the user of this template will enter these rows in many sessions. It means that he will enter data, save the file, close it, reopen it, enter some new rows and eventually try to commit these rows when he thinks he is done. What I noticed is that when the Excel file created from the template is reopened, the DataSource property of my ListObject controls is null. Which means I have no way to get back the data from the ListObject into a BindingList<MyCustomType>. I have been searching and I found no automatic way to do that and I don't really want to make a piece of code that would crawl through all of the columns to recreate my MyCustomType instances. In an ideal world I would have done like this.
private void OnStartup(object sender, System.EventArgs e)
{
ExcelTools.ListObject myCustomTypeTable = this.MyCustomTypeData;
BindingList<MyCustomType> customTypes = null;
if (myCustomTypeTable.DataSource == null) // Will always be null and erase previous data.
{
customTypes = new BindingList<MyCustomType>();
myCustomTypeTable.SetDataBinding(customTypes);
}
else
{
customTypes = myCustomTypeTable.DataSource as BindingList<MyCustomType>;
}
}
I have been doing a lot of research on this but I was not able to find a solution so I hope some of your can help me to resolve this issue.
Thanks.
As a last solution I decided that I would serialize my object list in XML and then add it as a XML custom part to my Excel file on save. But when I got into MSDN documentation to achieve this, I found out that there was 2 ways to persist data: XML custom part and data caching. And actually data caching was exactly the functionality I was looking for.
So I have been able to achieve my goal by simply using the CachedAttribute.
public partial class MyCustomTypesSheet
{
[Cached]
public BindingList<MyCustomType> MyCustomTypesDataSource { get; set; }
private void OnStartup(object sender, System.EventArgs e)
{
ExcelTools.ListObject myCustomTypeTable = this.MyCustomTypeData;
if (this.MyCustomTypesDataSource == null)
{
this.MyCustomTypesDataSource = new BindingList<MyCustomType>();
this.MyCustomTypesDataSource.Add(new MyCustomType());
}
myCustomTypeTable.SetDataBinding(this.MyCustomTypesDataSource);
}
private void InternalStartup()
{
this.Startup += new System.EventHandler(OnStartup);
}
}
It works like a charm. You can find more information about data caching in MSDN documentation.

Resources