/*
* Copyright 2005 Joe Walker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.directwebremoting.extend;
import java.util.Collection;
import java.util.Map;
import org.directwebremoting.util.LocalUtil;
/**
* An OutboundVariable that declares a JavaScript object
* @author Joe Walker [joe at getahead dot ltd dot uk]
*/
public class ObjectOutboundVariable extends NestedOutboundVariable
{
/**
* Constructor for when we have a Javascript type to populate
*/
public ObjectOutboundVariable(OutboundContext context, Class<?> type, String scriptClassName)
{
super(context);
if (context.isJsonMode())
{
if (scriptClassName != null)
{
throw new JsonModeMarshallException(type, "Can't used named Javascript objects in JSON mode");
}
}
this.scriptClassName = scriptClassName;
this.isNamed = scriptClassName != null && scriptClassName.length() > 0;
}
/**
* Constructor for when we don't have a Javascript type to populate
*/
public ObjectOutboundVariable(OutboundContext context)
{
super(context);
this.scriptClassName = null;
this.isNamed = false;
}
/* (non-Javadoc)
* @see org.directwebremoting.extend.NestedOutboundVariable#setChildren(java.util.Collection)
*/
@Override
public void setChildren(Collection<OutboundVariable> children)
{
throw new IllegalStateException("Use ObjectOutboundVariable.setChildren(Map<String, OutboundVariable>)");
}
/**
* We setup the children later than construction time so we can check for
* recursive references.
*/
public void setChildren(Map<String, OutboundVariable> childMap)
{
this.childMap = childMap;
super.setChildren(childMap.values());
}
/* (non-Javadoc)
* @see org.directwebremoting.extend.NestedOutboundVariable#getDeclareCode()
*/
public String getDeclareCode()
{
if (isInline())
{
return getChildDeclareCodes();
}
else
{
if (!isNamed)
{
return getChildDeclareCodes() + "var " + getVariableName() + "={};";
}
else
{
return getChildDeclareCodes() + "var " + getVariableName() + "=new " + scriptClassName + "();";
}
}
}
/* (non-Javadoc)
* @see org.directwebremoting.extend.OutboundVariable#getBuildCode()
*/
public String getBuildCode()
{
if (isInline())
{
return getChildBuildCodes();
}
else
{
StringBuffer buildCode = new StringBuffer(getChildBuildCodes());
String variableName = getVariableName();
for (Map.Entry<String, OutboundVariable> entry : childMap.entrySet())
{
String name = entry.getKey();
OutboundVariable nested = entry.getValue();
String nestedAssignCode = nested.getAssignCode();
// The semi-compact syntax is only any good for simple names
if (LocalUtil.isSimpleName(name))
{
buildCode.append(variableName);
buildCode.append('.');
buildCode.append(name);
buildCode.append('=');
buildCode.append(nestedAssignCode);
buildCode.append(';');
}
else
{
buildCode.append(variableName);
buildCode.append("['");
buildCode.append(name);
buildCode.append("']=");
buildCode.append(nestedAssignCode);
buildCode.append(';');
}
}
buildCode.append("\r\n");
return buildCode.toString();
}
}
/* (non-Javadoc)
* @see org.directwebremoting.extend.OutboundVariable#getAssignCode()
*/
public String getAssignCode()
{
if (isInline())
{
StringBuffer buffer = new StringBuffer();
if (isNamed)
{
buffer.append("dwr.engine.remote.newObject(\"");
buffer.append(scriptClassName);
buffer.append("\",{");
}
else
{
buffer.append('{');
}
boolean first = true;
for (Map.Entry<String, OutboundVariable> entry : childMap.entrySet())
{
String name = entry.getKey();
OutboundVariable nested = entry.getValue();
String innerAssignCode = nested.getAssignCode();
if (!first)
{
buffer.append(',');
}
// The compact syntax is only any good for simple names, when
// we are not recursive, and when we're not doing JSON
if (LocalUtil.isSimpleName(name) && !isJsonMode())
{
buffer.append(name);
buffer.append(':');
buffer.append(innerAssignCode);
}
else
{
buffer.append('\"');
buffer.append(name);
buffer.append("\":");
buffer.append(innerAssignCode);
}
// we don't need to do this one the hard way
first = false;
}
if (isNamed)
{
buffer.append("})");
}
else
{
buffer.append('}');
}
return buffer.toString();
}
else
{
return getVariableName();
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "ObjectOutboundVariable:" + childMap;
}
/**
* Are we named (or does {@link #scriptClassName} have some contents)
*/
private final boolean isNamed;
/**
* The name of this typed class if there is one
*/
private final String scriptClassName;
/**
* The contained variables
*/
private Map<String, OutboundVariable> childMap;
}