/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.commons.utils;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;
/**
* <p>
* This class defines the common functionalities for the serializable subclasses of {@link PageList}. Note that itself it does
* not implement the {@link java.io.Serializable} interface for the reason that it needs to define a no arg constructor in a non
* serializble class (serialization constraint).
* </p>
*
* <p>
* The method defines an abstract {@link #connect()} method that is used to connect the the page list to the underlying data.
* </p>
*
* <p>
* The methods {@link #readState(java.io.ObjectInputStream)} and {@link #writeState(java.io.ObjectOutputStream)} are defined for
* the subclasses and should be called by <code>void readObject(ObjectInputStream in)</code> and
* <code>void writeObject(ObjectOutputStream out)</code> custom serialization protocol.
* </p>
*
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
* @version $Revision$
*/
public abstract class AbstractSerializablePageList<E> extends PageList<E> {
/** . */
private static final Field pageSizeField;
static {
try {
pageSizeField = PageList.class.getDeclaredField("pageSize_");
pageSizeField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
/**
* Builds a page list.
*
* @param pageSize the page size
*/
protected AbstractSerializablePageList(int pageSize) {
super(pageSize);
}
/**
* This constructor should not be used by subclasses, it is only for serialization needs.
*/
protected AbstractSerializablePageList() {
super(10);
}
/** . */
private LazyList<E> lazyList;
protected abstract ListAccess<E> connect() throws Exception;
private void ensureCorrectState() {
if (lazyList == null) {
try {
lazyList = new LazyList<E>(connect(), super.getPageSize());
} catch (Exception e) {
throw new UndeclaredThrowableException(e);
}
// Save temporarily the current page
int currentPage = currentPage_;
// Refresh state
super.setAvailablePage(lazyList.size());
// Put back current page that was written by previous method call
if (currentPage != -1) {
currentPage_ = currentPage;
}
}
}
@Override
protected final void populateCurrentPage(int page) throws Exception {
// Make sure we have correct state
ensureCorrectState();
//
int from = getFrom();
int to = getTo();
currentListPage_ = lazyList.subList(from, to);
}
@Override
public final List<E> getAll() {
ensureCorrectState();
//
return lazyList;
}
// Serialization : should be used by subclasses
protected final void writeState(ObjectOutputStream out) throws IOException {
int pageSize;
try {
pageSize = pageSizeField.getInt(this);
} catch (IllegalAccessException e) {
InvalidObjectException ioe = new InvalidObjectException("Cannot set page size");
ioe.initCause(e);
throw ioe;
}
//
out.writeInt(pageSize);
out.writeInt(currentPage_);
}
protected final void readState(ObjectInputStream in) throws IOException {
try {
pageSizeField.setInt(this, in.readInt());
} catch (IllegalAccessException e) {
InvalidObjectException ioe = new InvalidObjectException("Cannot set page size");
ioe.initCause(e);
throw ioe;
}
currentPage_ = in.readInt();
}
// Intercept all method calls
@Override
public final int getAvailablePage() {
ensureCorrectState();
return super.getAvailablePage();
}
@Override
public final int getTo() {
ensureCorrectState();
return super.getTo();
}
@Override
public final int getFrom() {
ensureCorrectState();
return super.getFrom();
}
@Override
protected final void setAvailablePage(int available) {
ensureCorrectState();
super.setAvailablePage(available);
}
@Override
protected final void checkAndSetPage(int page) throws Exception {
ensureCorrectState();
super.checkAndSetPage(page);
}
@Override
public final List<E> getPage(int page) throws Exception {
ensureCorrectState();
return super.getPage(page);
}
@Override
public final List<E> currentPage() throws Exception {
ensureCorrectState();
return super.currentPage();
}
@Override
public final int getAvailable() {
ensureCorrectState();
return super.getAvailable();
}
@Override
public final int getCurrentPage() {
ensureCorrectState();
return super.getCurrentPage();
}
@Override
public final void setPageSize(int pageSize) {
ensureCorrectState();
super.setPageSize(pageSize);
}
@Override
public final int getPageSize() {
ensureCorrectState();
return super.getPageSize();
}
}