/*
* 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.services.jcr.impl.dataflow.serialization;
import org.exoplatform.services.jcr.JcrImplBaseTest;
import org.exoplatform.services.jcr.dataflow.ChangesLogIterator;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
import org.exoplatform.services.jcr.dataflow.TransactionChangesLog;
import org.exoplatform.services.jcr.dataflow.serialization.UnknownClassIdException;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.dataflow.SpoolConfig;
import org.exoplatform.services.jcr.impl.dataflow.persistent.FilePersistedValueData;
import org.exoplatform.services.jcr.impl.dataflow.persistent.StreamPersistedValueData;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Created by The eXo Platform SAS. <br>Date: 16.02.2009
*
* @author <a href="mailto:alex.reshetnyak@exoplatform.com.ua">Alex Reshetnyak</a>
* @version $Id: JcrImplSerializationBaseTest.java 111 2008-11-11 11:11:11Z
* rainf0x $
*/
public abstract class JcrImplSerializationBaseTest extends JcrImplBaseTest
{
protected void checkIterator(Iterator<ItemState> expected, Iterator<ItemState> changes) throws Exception
{
while (expected.hasNext())
{
assertTrue(changes.hasNext());
ItemState expect = expected.next();
ItemState elem = changes.next();
assertEquals(expect.getState(), elem.getState());
// assertEquals(expect.getAncestorToSave(), elem.getAncestorToSave());
ItemData expData = expect.getData();
ItemData elemData = elem.getData();
assertEquals(expData.getQPath(), elemData.getQPath());
assertEquals(expData.isNode(), elemData.isNode());
assertEquals(expData.getIdentifier(), elemData.getIdentifier());
assertEquals(expData.getParentIdentifier(), elemData.getParentIdentifier());
if (!expData.isNode())
{
PropertyData expProp = (PropertyData)expData;
PropertyData elemProp = (PropertyData)elemData;
assertEquals(expProp.getType(), elemProp.getType());
assertEquals(expProp.isMultiValued(), elemProp.isMultiValued());
List<ValueData> expValDat = expProp.getValues();
List<ValueData> elemValDat = elemProp.getValues();
// Both value data are null
if (expValDat != null && elemValDat != null)
{
assertEquals(expValDat.size(), elemValDat.size());
for (int j = 0; j < expValDat.size(); j++)
{
// are of the same class
assertEquals(expValDat.get(j).getClass(), elemValDat.get(j).getClass());
//
if (expValDat.get(j) instanceof FilePersistedValueData)
{
// if files in both instances are null
Boolean nullFiles =
((FilePersistedValueData)expValDat.get(j)).getFile() == null
&& ((FilePersistedValueData)elemValDat.get(j)).getFile() == null;
// if there are instances of StreamPersistedValueData
if (expValDat.get(j) instanceof StreamPersistedValueData)
{
// and they both have null spool files
nullFiles &=
((StreamPersistedValueData)expValDat.get(j)).getTempFile() == null
&& ((StreamPersistedValueData)elemValDat.get(j)).getTempFile() == null;
}
if (nullFiles)
{
// Both value data are equals
continue;
}
}
assertTrue(java.util.Arrays.equals(expValDat.get(j).getAsByteArray(), elemValDat.get(j)
.getAsByteArray()));
// check is received property values ReplicableValueData
// assertTrue(elemValDat.get(j) instanceof ReplicableValueData);
}
}
}
}
assertFalse(changes.hasNext());
}
protected void checkResults(List<TransactionChangesLog> srcLog) throws Exception
{
File jcrfile = serializeLogs(srcLog);
List<TransactionChangesLog> destLog = deSerializeLogs(jcrfile);
assertEquals(srcLog.size(), destLog.size());
for (int i = 0; i < srcLog.size(); i++)
{
checkIterator(srcLog.get(i).getAllStates().iterator(), destLog.get(i).getAllStates().iterator());
}
}
protected File serializeLogs(List<TransactionChangesLog> logs) throws IOException, UnknownClassIdException
{
File jcrfile = File.createTempFile("jcr", "test");
ObjectWriterImpl jcrout = new ObjectWriterImpl(new FileOutputStream(jcrfile));
TransactionChangesLogWriter wr = new TransactionChangesLogWriter();
for (TransactionChangesLog tcl : logs)
{
wr.write(jcrout, tcl);
}
jcrout.flush();
jcrout.close();
return jcrfile;
}
protected List<TransactionChangesLog> deSerializeLogs(File jcrfile) throws IOException, UnknownClassIdException
{
ObjectReaderImpl jcrin = new ObjectReaderImpl(new FileInputStream(jcrfile));
List<TransactionChangesLog> readed = new ArrayList<TransactionChangesLog>();
try
{
while (true)
{
TransactionChangesLog obj =
(new TransactionChangesLogReader(SpoolConfig.getDefaultSpoolConfig(), holder)).read(jcrin);
// TransactionChangesLog obj = new TransactionChangesLog();
// obj.readObject(jcrin);
readed.add(obj);
}
}
catch (EOFException e)
{
// ok
}
//Imitation of save.
imitationSave(readed);
return readed;
}
/**
* Imitation of JCR save
*
* @param readed
* @return
* @throws IOException
*/
private void imitationSave(List<TransactionChangesLog> readed) throws IOException
{
for (TransactionChangesLog tLog : readed)
{
ChangesLogIterator it = tLog.getLogIterator();
while (it.hasNextLog())
{
PlainChangesLog pLog = it.nextLog();
for (ItemState state : pLog.getAllStates())
{
ItemData itemData = state.getData();
if (!itemData.isNode())
{
PropertyData propData = (PropertyData)itemData;
if (propData.getValues() != null)
{
for (ValueData valueData : propData.getValues())
{
if (valueData instanceof StreamPersistedValueData)
{
// imitation of JCR save
if (((StreamPersistedValueData)valueData).getTempFile() != null)
{
((StreamPersistedValueData)valueData)
.setPersistedFile(((StreamPersistedValueData)valueData).getTempFile());
}
else
{
File file = File.createTempFile("tempFile", "tmp");
file.deleteOnExit();
if (((StreamPersistedValueData)valueData).getStream() != null)
{
copy(((StreamPersistedValueData)valueData).getStream(), new FileOutputStream(file));
((StreamPersistedValueData)valueData).setPersistedFile(file);
}
}
}
}
}
}
}
}
}
}
protected long copy(InputStream in, OutputStream out) throws IOException
{
// compare classes as in Java6 Channels.newChannel(), Java5 has a bug in newChannel().
boolean inFile = in instanceof FileInputStream && FileInputStream.class.equals(in.getClass());
boolean outFile = out instanceof FileOutputStream && FileOutputStream.class.equals(out.getClass());
if (inFile && outFile)
{
// it's user file
FileChannel infch = ((FileInputStream)in).getChannel();
FileChannel outfch = ((FileOutputStream)out).getChannel();
long size = 0;
long r = 0;
do
{
r = outfch.transferFrom(infch, r, infch.size());
size += r;
}
while (r < infch.size());
return size;
}
else
{
// it's user stream (not a file)
ReadableByteChannel inch = inFile ? ((FileInputStream)in).getChannel() : Channels.newChannel(in);
WritableByteChannel outch = outFile ? ((FileOutputStream)out).getChannel() : Channels.newChannel(out);
long size = 0;
int r = 0;
ByteBuffer buff = ByteBuffer.allocate(32 * 1024);
buff.clear();
while ((r = inch.read(buff)) >= 0)
{
buff.flip();
// copy all
do
{
outch.write(buff);
}
while (buff.hasRemaining());
buff.clear();
size += r;
}
if (outFile)
{
((FileChannel)outch).force(true); // force all data to FS
}
return size;
}
}
}