package org.carlspring.strongbox.xml.parsers;
import org.carlspring.strongbox.url.ClasspathURLStreamHandler;
import org.carlspring.strongbox.url.ClasspathURLStreamHandlerFactory;
import org.carlspring.strongbox.xml.CustomTagService;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
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.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author mtodorov
*/
public class GenericParser<T>
{
public final static boolean IS_OUTPUT_FORMATTED = true;
private static final Logger logger = LoggerFactory.getLogger(GenericParser.class);
private ReentrantLock lock = new ReentrantLock();
private Set<Class> classes = new LinkedHashSet<>();
private JAXBContext context;
static
{
final ClasspathURLStreamHandler handler = new ClasspathURLStreamHandler(ClassLoader.getSystemClassLoader());
ClasspathURLStreamHandlerFactory factory = new ClasspathURLStreamHandlerFactory("classpath", handler);
try
{
URL.setURLStreamHandlerFactory(factory);
}
catch (Error e)
{
// You can safely disregard this, as a second attempt to register a an already
// registered URLStreamHandlerFactory will throw an error. Since there's no
// apparent way to check if it's registered, just catch and ignore the error.
}
}
public GenericParser()
{
this.classes.addAll(CustomTagService.getInstance().getImplementations());
}
public GenericParser(boolean useServiceLoader)
{
if (useServiceLoader)
{
this.classes.addAll(CustomTagService.getInstance().getImplementations());
}
}
public GenericParser(boolean useServiceLoader, Class... classes)
{
Collections.addAll(this.classes, classes);
if (useServiceLoader)
{
this.classes.addAll(CustomTagService.getInstance().getImplementations());
}
}
public GenericParser(Class... classes)
{
Collections.addAll(this.classes, classes);
this.classes.addAll(CustomTagService.getInstance().getImplementations());
}
public T parse(File file)
throws JAXBException, IOException
{
T object = null;
try (FileInputStream is = new FileInputStream(file))
{
object = parse(is);
}
return object;
}
public T parse(URL url)
throws IOException, JAXBException
{
try (InputStream is = url.openStream())
{
return parse(is);
}
}
public T parse(InputStream is)
throws JAXBException
{
T object = null;
try
{
lock.lock();
Unmarshaller unmarshaller = getContext().createUnmarshaller();
//noinspection unchecked
object = (T) unmarshaller.unmarshal(is);
}
finally
{
lock.unlock();
}
return object;
}
public void store(T object,
String path)
throws JAXBException, IOException
{
store(object, new File(path).getAbsoluteFile());
}
public void store(T object,
File file)
throws JAXBException, IOException
{
try (FileOutputStream os = new FileOutputStream(file))
{
store(object, os);
}
}
public void store(T object,
OutputStream os)
throws JAXBException
{
try
{
lock.lock();
JAXBContext context = getContext();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, IS_OUTPUT_FORMATTED);
marshaller.marshal(object, os);
}
finally
{
lock.unlock();
}
}
/**
* Serialize #object to String using JAXB marshaller.
*
* @param object the object to be serialized
* @return String representation of object
*/
public String serialize(T object)
throws JAXBException
{
StringWriter writer = new StringWriter();
try
{
lock.lock();
JAXBContext context = getContext();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, IS_OUTPUT_FORMATTED);
marshaller.marshal(object, writer);
return writer.getBuffer().toString();
}
finally
{
lock.unlock();
}
}
@SuppressWarnings("unchecked")
public T deserialize(String input)
throws JAXBException
{
try
{
lock.lock();
JAXBContext context = getContext();
Unmarshaller m = context.createUnmarshaller();
return (T) m.unmarshal(new StringReader(input));
}
finally
{
lock.unlock();
}
}
public void setContext(Class<?> classType)
throws JAXBException
{
context = JAXBContext.newInstance(classType);
}
public JAXBContext getContext()
throws JAXBException
{
if (context == null)
{
try
{
context = JAXBContext.newInstance(classes.toArray(new Class[classes.size()]));
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
return context;
}
}