/**
*
*/
package org.jboss.portletbridge.richfaces;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import javax.portlet.MimeResponse;
import javax.portlet.ResourceURL;
import javax.portlet.faces.Bridge;
import javax.portlet.faces.BridgeUtil;
import org.ajax4jsf.Messages;
import org.ajax4jsf.resource.FacesResourceContext;
import org.ajax4jsf.resource.InternetResource;
import org.ajax4jsf.resource.InternetResourceBuilder;
import org.ajax4jsf.resource.ResourceContext;
import org.ajax4jsf.resource.ResourceNotFoundException;
import org.ajax4jsf.resource.ResourceRenderer;
import org.ajax4jsf.resource.ScriptRenderer;
import org.ajax4jsf.resource.TemplateCSSRenderer;
import org.ajax4jsf.util.base64.Codec;
import org.jboss.portletbridge.context.PortalActionURL;
import org.jboss.portletbridge.context.PortletExternalContextImpl;
import org.jboss.portletbridge.util.BridgeLogger;
import org.jboss.portletbridge.util.PlatformUtil;
/**
* @author asmirnov
*
*/
public class PortletResourceBuilder extends InternetResourceBuilder {
public static final String RFRES = "/org.rf.res";
private static final int RFRES_LENGTH = RFRES.length();
private static final String DATA_SEPARATOR = "/DA/";
private static final String DATA_BYTES_SEPARATOR = "/DB/";
static final Pattern RESOURCE_PATTERN = Pattern.compile("^" + RFRES
+ "(.+)(?:/D(A|B)/(.*))$");
private static final Logger log = BridgeLogger.AJAX.getLogger();
private final InternetResourceBuilder parent;
private final ResourceRenderer scriptRenderer;
private final Codec codec = new Codec();
/**
* @param parent
*/
public PortletResourceBuilder(InternetResourceBuilder parent) {
super();
this.parent = parent;
this.scriptRenderer = new PortletScriptRenderer(
parent.getScriptRenderer());
}
public String getUri(InternetResource resource, FacesContext context,
Object storeData) {
if (BridgeUtil.isPortletRequest() && !specialResource(resource)) {
Object response = context.getExternalContext().getResponse();
if (response instanceof MimeResponse) {
MimeResponse mimeResponse = (MimeResponse) response;
ResourceURL resourceURL = PlatformUtil
.createResourceURL(mimeResponse);
FacesResourceContext resourceContext = new FacesResourceContext(
context);
resourceContext.setResourceData(storeData);
if (resource.isCacheable(resourceContext)) {
try {
// resourceURL.setCacheability(ResourceURL.FULL);
} catch (IllegalStateException e) {
// Ignore that, use default cache level.
}
}
StringBuffer uri = new StringBuffer(RFRES);// ResourceServlet.DEFAULT_SERVLET_PATH).append("/");
uri.append(resource.getKey());
// append serialized data as Base-64 encoded request string.
if (storeData != null) {
try {
byte[] objectData;
if (storeData instanceof byte[]) {
objectData = (byte[]) storeData;
uri.append(DATA_BYTES_SEPARATOR);
} else {
ByteArrayOutputStream dataSteram = new ByteArrayOutputStream(
1024);
ObjectOutputStream objStream = new ObjectOutputStream(
dataSteram);
objStream.writeObject(storeData);
objStream.flush();
objStream.close();
dataSteram.close();
objectData = dataSteram.toByteArray();
uri.append(DATA_SEPARATOR);
}
byte[] dataArray = encrypt(objectData);
uri.append(new String(dataArray, "ISO-8859-1"));
// / byte[] objectData = dataSteram.toByteArray();
// / uri.append("?").append(new
// String(Base64.encodeBase64(objectData),
// / "ISO-8859-1"));
} catch (Exception e) {
// Ignore errors, log it
log.log(Level.SEVERE,
Messages.getMessage(Messages.QUERY_STRING_BUILDING_ERROR),
e);
}
}
resourceURL.setResourceID(uri.toString());
return resourceURL.toString().replaceAll("\\&\\;", "&");
} else {
return PortletExternalContextImpl.RESOURCE_URL_DO_NOTHITG;
}
} else {
return getDefaultUri(resource, context, storeData);
}
}
private String getDefaultUri(InternetResource resource,
FacesContext context, Object storeData) {
String uri = parent.getUri(resource, context, storeData);
PortalActionURL portalUrl;
try {
portalUrl = new PortalActionURL(uri);
} catch (MalformedURLException e) {
return uri;
}
portalUrl.removeParameter(Bridge.DIRECT_LINK);
return portalUrl.toString();
}
private static final String[] specialResources = { "/tiny_mce/",
"scripts/editor.js", "org/richfaces/renderkit/html/1$1" };
private boolean specialResource(InternetResource resource) {
String key = resource.getKey();
for (String special : specialResources) {
if (key.contains(special)) {
return true;
}
}
return false;
}
/**
* @param resourceId
* @return
* @throws ResourceNotFoundException
* @see org.ajax4jsf.resource.InternetResourceBuilder#getResourceForKey(java.lang.String)
*/
public InternetResource getResourceForKey(String resourceId)
throws ResourceNotFoundException {
Matcher matcher = RESOURCE_PATTERN.matcher(resourceId);
String key;
InternetResource resource;
if (matcher.matches()) {
key = matcher.group(1);
resource = parent.getResourceForKey(key);
} else if (resourceId.startsWith(RFRES)) {
key = resourceId.substring(RFRES_LENGTH);
resource = parent.getResourceForKey(key);
} else {
resource = parent.getResourceForKey(resourceId);
}
checkRenderer(resource);
return resource;
}
@Override
public Object getResourceDataForKey(String key) {
Object data = null;
if (null != key) {
Matcher matcher = RESOURCE_PATTERN.matcher(key);
if (matcher.matches()) {
String dataString = matcher.group(3);
if (log.isLoggable(Level.FINE)) {
log.fine(Messages.getMessage(
Messages.RESTORE_DATA_FROM_RESOURCE_URI_INFO, key,
dataString));
}
byte[] objectArray = null;
try {
byte[] dataArray = dataString.getBytes("ISO-8859-1");
objectArray = decrypt(dataArray);
if ("B".equals(matcher.group(2))) {
data = objectArray;
} else {
try {
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(objectArray));
data = in.readObject();
} catch (StreamCorruptedException e) {
log.log(Level.SEVERE,
Messages.getMessage(Messages.STREAM_CORRUPTED_ERROR),
e);
} catch (IOException e) {
log.log(Level.SEVERE,
Messages.getMessage(Messages.DESERIALIZE_DATA_INPUT_ERROR),
e);
} catch (ClassNotFoundException e) {
log.log(Level.SEVERE,
Messages.getMessage(Messages.DATA_CLASS_NOT_FOUND_ERROR),
e);
}
}
} catch (UnsupportedEncodingException e1) {
// should never happen, default encoding always presented.
}
} else {
data = parent.getResourceDataForKey(key);
}
}
return data;
}
protected byte[] encrypt(byte[] src) {
try {
Deflater compressor = new Deflater(Deflater.BEST_SPEED);
byte[] compressed = new byte[src.length + 100];
compressor.setInput(src);
compressor.finish();
int totalOut = compressor.deflate(compressed);
byte[] zipsrc = new byte[totalOut];
System.arraycopy(compressed, 0, zipsrc, 0, totalOut);
compressor.end();
return codec.encode(zipsrc);
} catch (Exception e) {
throw new FacesException("Error encode resource data", e);
}
}
protected byte[] decrypt(byte[] src) {
try {
byte[] zipsrc = codec.decode(src);
Inflater decompressor = new Inflater();
byte[] uncompressed = new byte[zipsrc.length * 5];
decompressor.setInput(zipsrc);
int totalOut = decompressor.inflate(uncompressed);
byte[] out = new byte[totalOut];
System.arraycopy(uncompressed, 0, out, 0, totalOut);
decompressor.end();
return out;
} catch (Exception e) {
throw new FacesException("Error decode resource data", e);
}
}
/**
* @param key
* @param resource
* @see org.ajax4jsf.resource.InternetResourceBuilder#addResource(java.lang.String,
* org.ajax4jsf.resource.InternetResource)
*/
public void addResource(String key, InternetResource resource) {
checkRenderer(resource);
parent.addResource(key, resource);
}
/**
* @param base
* @param path
* @return
* @throws FacesException
* @see org.ajax4jsf.resource.InternetResourceBuilder#createResource(java.lang.Object,
* java.lang.String)
*/
public InternetResource createResource(Object base, String path)
throws FacesException {
InternetResource resource = parent.createResource(base, path);
checkRenderer(resource);
return resource;
}
private void checkRenderer(InternetResource resource) {
if (null != resource) {
synchronized (resource) {
ResourceRenderer resourceRenderer = resource.getRenderer(null);
if (null != resourceRenderer) {
if (resourceRenderer instanceof ScriptRenderer) {
resource.setRenderer(new PortletScriptRenderer(
resourceRenderer));
} else if (TemplateCSSRenderer.class
.equals(resourceRenderer.getClass())) {
resource.setRenderer(new PotrletTemplateCSSRenderer());
}
}
}
}
}
/**
* @param cacheable
* @param session
* @param mime
* @return
* @throws FacesException
* @see org.ajax4jsf.resource.InternetResourceBuilder#createUserResource(boolean,
* boolean, java.lang.String)
*/
public InternetResource createUserResource(boolean cacheable,
boolean session, String mime) throws FacesException {
return parent.createUserResource(cacheable, session, mime);
}
/**
* @param path
* @return
* @throws ResourceNotFoundException
* @see org.ajax4jsf.resource.InternetResourceBuilder#getResource(java.lang.String)
*/
public InternetResource getResource(String path)
throws ResourceNotFoundException {
InternetResource resource = parent.getResource(path);
checkRenderer(resource);
return resource;
}
public ResourceRenderer getScriptRenderer() {
return scriptRenderer;
}
/**
* @return
* @see org.ajax4jsf.resource.InternetResourceBuilder#getStartTime()
*/
public long getStartTime() {
return parent.getStartTime();
}
/**
* @return
* @see org.ajax4jsf.resource.InternetResourceBuilder#getStyleRenderer()
*/
public ResourceRenderer getStyleRenderer() {
return parent.getStyleRenderer();
}
/**
* @throws FacesException
* @see org.ajax4jsf.resource.InternetResourceBuilder#init()
*/
public void init() throws FacesException {
parent.init();
}
}