/**
* This file Copyright (c) 2005-2007 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain Eclipse Public Licensed code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.core.model;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Map;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;
import com.aptana.ide.core.ILoggable;
import com.aptana.ide.core.ILogger;
import com.aptana.ide.core.StringUtils;
import com.aptana.ide.core.xpath.XPathUtils;
/**
* @author Kevin Sawicki (ksawicki@aptana.com)
*/
public abstract class CoreModelObject extends BaseModelObject implements ILocationObject, ISynchronizableObject,
ILoggable, ITransformObject
{
/**
* XPATH
*/
protected static final XPath XPATH = XPathFactory.newInstance().newXPath();
/**
* ID_ELEMENT
*/
public static final String ID_ELEMENT = "id"; //$NON-NLS-1$
/**
* URLS
*/
public static final String URLS = "urls"; //$NON-NLS-1$
/**
* URL
*/
public static final String URL = "url"; //$NON-NLS-1$
/**
* PATHS
*/
public static final String PATHS = "paths"; //$NON-NLS-1$
/**
* PATH
*/
public static final String PATH = "path"; //$NON-NLS-1$
/**
* NAME
*/
public static final String NAME = "name"; //$NON-NLS-1$
/**
* VALUE
*/
public static final String VALUE = "value"; //$NON-NLS-1$
/**
* Id of this object
*/
protected String id;
/**
* Service provider
*/
protected IServiceProvider provider;
/**
* Service request builder
*/
protected IServiceRequestBuilder builder;
/**
* Location
*/
protected URL location = null;
/**
* Default location
*/
protected URL defaultLocation = null;
/**
* Logger
*/
protected ILogger logger;
private int lastUpdateStatus = IServiceResponse.STATUS_UNSET;
/**
* Last service errors
*/
protected ServiceErrors lastErrors;
/**
* Creates a new core model object with a null id
*/
public CoreModelObject()
{
this.id = null;
}
/**
* Gets the item string to use for the XPath
*
* @return - item element string
*/
protected abstract String getItemString();
/**
* @see com.aptana.ide.core.model.ILocationObject#getDefaultLocation()
*/
public URL getDefaultLocation()
{
return this.defaultLocation;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#getLocation()
*/
public URL getLocation()
{
if (this.location == null && this.defaultLocation != null)
{
return defaultLocation;
}
return this.location;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#getRequestBuilder()
*/
public IServiceRequestBuilder getRequestBuilder()
{
return this.builder;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#getServiceProvider()
*/
public IServiceProvider getServiceProvider()
{
return this.provider;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#hasLocation()
*/
public boolean hasLocation()
{
return this.location != null && !this.location.equals(this.defaultLocation);
}
/**
* @see com.aptana.ide.core.model.ILocationObject#setDefaultLocation(java.net.URL)
*/
public void setDefaultLocation(URL defaultLocation)
{
this.defaultLocation = defaultLocation;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#setLocation(java.net.URL)
*/
public void setLocation(URL location)
{
if (isModelChanged(this.location, location))
{
this.location = location;
fireChange();
}
}
/**
* @see com.aptana.ide.core.model.ITransformObject#fromXML(java.lang.String)
*/
public synchronized void fromXML(String xml)
{
try
{
XPath xpath = XPathUtils.getNewXPath();
Node site = (Node) xpath.evaluate("/" + getItemString(), XPathUtils.createSource(xml), XPathConstants.NODE); //$NON-NLS-1$
fromNode(site);
}
catch (XPathExpressionException e1)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Error_Building_XML"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
e1.getMessage()
}
);
logError(message);
}
}
/**
* @see com.aptana.ide.core.model.ILocationObject#setRequestBuilder(com.aptana.ide.core.model.IServiceRequestBuilder)
*/
public void setRequestBuilder(IServiceRequestBuilder builder)
{
this.builder = builder;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#setServiceProvider(com.aptana.ide.core.model.IServiceProvider)
*/
public void setServiceProvider(IServiceProvider provider)
{
this.provider = provider;
}
/**
* Gets the prefix to put before logging statements
*
* @return - prefix
*/
public abstract String getLoggingPrefix();
/**
* Calls perform action with IServiceRequest.UPLOAD as the type
*
* @param nameValuePairs
*/
public void performUploadAction(Map<String, String> nameValuePairs)
{
this.performAction(nameValuePairs, IServiceRequest.UPLOAD);
}
/**
* Calls perform action with IServiceRequest.UPLOAD as the type
*
* @param name
* @param value
*/
public void performUploadAction(String name, String value)
{
this.performAction(name, value, IServiceRequest.UPLOAD);
}
/**
* Calls perform action with IServiceRequest.UPLOAD as the type
*
* @param nameValuePairs
*/
public void performUploadAction(String nameValuePairs)
{
this.performAction(nameValuePairs, IServiceRequest.UPLOAD);
}
/**
* Calls perform action with IServiceRequest.UPDATE as the type
*
* @param nameValuePairs
*/
public void performUpdateAction(Map<String, String> nameValuePairs)
{
this.performAction(nameValuePairs, IServiceRequest.UPDATE);
}
/**
* Calls perform action with IServiceRequest.UPDATE as the type
*
* @param name
* @param value
*/
public void performUpdateAction(String name, String value)
{
this.performAction(name, value, IServiceRequest.UPDATE);
}
/**
* Calls perform action with IServiceRequest.UPDATE as the type
*
* @param nameValuePairs
*/
public void performUpdateAction(String nameValuePairs)
{
this.performAction(nameValuePairs, IServiceRequest.UPDATE);
}
/**
* @see com.aptana.ide.core.model.ISynchronizableObject#performAction(java.util.Map, java.lang.String)
*/
public IServiceErrors performAction(Map<String, String> nameValuePairs, String type)
{
StringBuffer query = new StringBuffer("?"); //$NON-NLS-1$
if (nameValuePairs != null)
{
for (String name : nameValuePairs.keySet())
{
String value = nameValuePairs.get(name);
query.append(name);
query.append('=');
query.append(value);
query.append('&');
}
}
return performAction(query.toString(), type);
}
/**
* @see com.aptana.ide.core.model.ISynchronizableObject#performAction(java.lang.String, java.lang.String,
* java.lang.String)
*/
public IServiceErrors performAction(String name, String value, String type)
{
return performAction(name + "=" + value, type); //$NON-NLS-1$
}
/**
* Calls with the response from perform action
*
* @param response
*/
protected void handleActionResponse(IServiceResponse response)
{
// Does nothing by default, subclasses should override
}
/**
* @see com.aptana.ide.core.model.ISynchronizableObject#performAction(java.lang.String, java.lang.String)
*/
public IServiceErrors performAction(String nameValuePairs, String type)
{
ServiceErrors errors = null;
if (hasLocation())
{
String query = ""; //$NON-NLS-1$
String baseURL = getLocation().toExternalForm();
if (baseURL.indexOf('?') == -1)
{
if (!nameValuePairs.startsWith("?")) //$NON-NLS-1$
{
query += "?"; //$NON-NLS-1$
}
}
else
{
query += "&"; //$NON-NLS-1$
}
query += nameValuePairs;
try
{
URL actionURL = new URL(baseURL + query);
if (this.provider != null && this.builder != null)
{
IServiceResponse response = null;
IServiceRequest request = this.builder.generateRequest(this, type);
if (request != null)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Perform_Action_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
request.getContents()
}
);
logInfo(message);
}
else
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Null_Request_On_Action"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix()
}
);
logInfo(message);
}
response = this.provider.callService(actionURL, request);
if (response != null)
{
String message1 = MessageFormat.format(
Messages.getString("CoreModelObject.Perform_Action_Response"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
String message2 = MessageFormat.format(
Messages.getString("CoreModelObject.Perform_Action_Status"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getStatus()
}
);
logInfo(message1);
logInfo(message2);
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
if (response.getStatus() != IServiceResponse.STATUS_OK
&& response.getStatus() != IServiceResponse.STATUS_UNKNOWN_HOST)
{
errors.fromXML(response.getContents());
}
handleActionResponse(response);
}
}
}
catch (MalformedURLException e)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Error_Creating_URL"), //$NON-NLS-1$
new Object [] {
e.getMessage()
}
);
logError(message);
}
}
setLastServiceErrors(errors);
return errors;
}
/**
* Logs an info message
*
* @param message
*/
protected void logInfo(String message)
{
if (this.logger != null)
{
this.logger.logInfo(message);
}
}
/**
* Logs an error message
*
* @param message
*/
protected void logError(String message)
{
if (this.logger != null)
{
this.logger.logError(message);
}
}
/**
* Logs an error message
*
* @param message
* @param th
*/
protected void logError(String message, Throwable th)
{
if (this.logger != null)
{
this.logger.logError(message, th);
}
}
/**
* Logs a warning message
*
* @param message
*/
protected void logWarning(String message)
{
if (this.logger != null)
{
this.logger.logWarning(message);
}
}
/**
* @see com.aptana.ide.core.model.ISynchronizableObject#commit()
*/
public IServiceErrors commit()
{
ServiceErrors errors = null;
if (this.provider != null && this.builder != null)
{
IServiceResponse response = null;
IServiceRequest request = this.builder.generateRequest(this, IServiceRequest.COMMIT);
if (request != null)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Commit_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
StringUtils.getPublishableMessage(request.getContents())
}
);
logInfo(message);
}
else
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Null_Request_On_Commit"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
}
);
logInfo(message);
}
if (hasLocation())
{
response = this.provider.callService(getLocation(), request);
}
else if (getDefaultLocation() != null)
{
response = this.provider.callService(getDefaultLocation(), request);
}
if (response != null)
{
String message1 = MessageFormat.format(
Messages.getString("CoreModelObject.Commit_Response"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
String message2 = MessageFormat.format(
Messages.getString("CoreModelObject.Commit_Reponse_Status"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getStatus()
}
);
logInfo(message1);
logInfo(message2);
if (response.getStatus() == IServiceResponse.STATUS_CREATED && response.getData() instanceof URL)
{
setLocation((URL) response.getData());
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
errors.setContents(response.getContents());
}
else if (response.getStatus() != IServiceResponse.STATUS_UNKNOWN_HOST)
{
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
errors.fromXML(response.getContents());
if (response.getStatus() == IServiceResponse.STATUS_OK)
{
fireChange();
}
}
}
}
setLastServiceErrors(errors);
return errors;
}
// This is a really ugly implementation that I just glued together using some of the other methods in this class
// to unblock Ian and get the job done for posts. It has not been tested for other methods. (kris)
public IServiceErrors xmlRest(String method)
{
ServiceErrors errors = null;
if (this.provider != null && this.builder != null)
{
IServiceResponse response = null;
IServiceRequest request = this.builder.generateRequest(this, method);
if (request != null)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.REST_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
request.getContents()
}
);
logInfo(message);
}
else
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Null_Request_On_XML_REST"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix()
}
);
logInfo(message);
}
if (hasLocation())
{
response = this.provider.callService(getLocation(), request);
}
else if (getDefaultLocation() != null)
{
response = this.provider.callService(getDefaultLocation(), request);
}
if (response != null)
{
String message1 = MessageFormat.format(
Messages.getString("CoreModelObject.XML_REST_Response"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
String message2 = MessageFormat.format(
Messages.getString("CoreModelObject.XML_REST_Response_Status"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getStatus()
}
);
logInfo(message1);
logInfo(message2);
if (response.getStatus() == IServiceResponse.STATUS_CREATED ||
response.getStatus() == IServiceResponse.STATUS_OK ||
response.getStatus() == IServiceResponse.STATUS_DELETED)
{
if (response.getData() instanceof String)
{
fromXML((String) response.getData());
}
else if (response.getData() instanceof URL)
{
setLocation((URL) response.getData());
}
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
}
else if (response.getStatus() != IServiceResponse.STATUS_UNKNOWN_HOST)
{
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
errors.fromXML(response.getContents());
}
}
}
setLastServiceErrors(errors);
return errors;
}
public IServiceErrors upload()
{
ServiceErrors errors = null;
if (this.provider != null && this.builder != null)
{
IServiceResponse response = null;
IServiceRequest request = this.builder.generateRequest(this, IServiceRequest.UPLOAD);
if (request != null)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Upload_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
request.getContents()
}
);
logInfo(message);
}
else
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Null_Request_On_Upload"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix()
}
);
logInfo(message);
}
if (hasLocation())
{
response = this.provider.callService(getLocation(), request);
}
else if (getDefaultLocation() != null)
{
response = this.provider.callService(getDefaultLocation(), request);
}
if (response != null)
{
String message1 = MessageFormat.format(
Messages.getString("CoreModelObject.Upload_Response"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
String message2 = MessageFormat.format(
Messages.getString("CoreModelObject.Upload_Response_Status"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
logInfo(message1);
logInfo(message2);
if (response.getStatus() == IServiceResponse.STATUS_CREATED && response.getData() instanceof URL)
{
setLocation((URL) response.getData());
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
}
else if (response.getStatus() != IServiceResponse.STATUS_UNKNOWN_HOST)
{
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
errors.fromXML(response.getContents());
if (response.getStatus() == IServiceResponse.STATUS_OK)
{
fireChange();
}
}
}
}
setLastServiceErrors(errors);
return errors;
}
/**
* @see com.aptana.ide.core.model.ISynchronizableObject#delete()
*/
public IServiceErrors delete()
{
ServiceErrors errors = null;
if (this.provider != null && this.builder != null)
{
IServiceResponse response = null;
IServiceRequest request = this.builder.generateRequest(this, IServiceRequest.DELETE);
if (request != null)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Delete_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
request.getContents()
}
);
logInfo(message);
}
else
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Null_Request_On_Delete_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix()
}
);
logInfo(message);
}
if (hasLocation())
{
response = this.provider.callService(getLocation(), request);
}
else if (getDefaultLocation() != null)
{
response = this.provider.callService(getDefaultLocation(), request);
}
if (response != null)
{
String message1 = MessageFormat.format(
Messages.getString("CoreModelObject.Delete_Reponse_Status"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
String message2 = MessageFormat.format(
Messages.getString("CoreModelObject.Delete_Response"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getContents()
}
);
logInfo(message1);
logInfo(message2);
if (response.getStatus() == IServiceResponse.STATUS_DELETED)
{
setLocation(null);
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
}
else if (response.getStatus() != IServiceResponse.STATUS_UNKNOWN_HOST)
{
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
errors.fromXML(response.getContents());
}
}
}
setLastServiceErrors(errors);
return errors;
}
/**
* @see com.aptana.ide.core.model.ISynchronizableObject#update()
*/
public IServiceErrors update()
{
ServiceErrors errors = null;
if (this.provider != null && this.builder != null)
{
IServiceResponse response = null;
IServiceRequest request = this.builder.generateRequest(this, IServiceRequest.UPDATE);
if (request != null)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Update_Content"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
request.getContents()
}
);
logInfo(message);
}
else
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.Null_Request_On_Update"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix()
}
);
logInfo(message);
}
if (hasLocation())
{
response = this.provider.callService(getLocation(), request);
}
else if (getDefaultLocation() != null)
{
response = this.provider.callService(getDefaultLocation(), request);
}
if (response != null)
{
lastUpdateStatus = response.getStatus();
String message1 = MessageFormat.format(
Messages.getString("CoreModelObject.Update_Response_Status"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
response.getStatus()
}
);
String message2 = MessageFormat.format(
Messages.getString("CoreModelObject.Update_Reponse"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
StringUtils.getPublishableMessage(response.getData())
}
);
logInfo(message1);
logInfo(message2);
if (response.getStatus() == IServiceResponse.STATUS_OK)
{
if (response.getData() instanceof String)
{
fromXML((String) response.getData());
}
else if (response.getData() instanceof URL)
{
setLocation((URL) response.getData());
}
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
}
else if (response.getStatus() != IServiceResponse.STATUS_UNKNOWN_HOST)
{
errors = new ServiceErrors();
errors.setStatus(response.getStatus());
errors.fromXML(response.getContents());
}
}
}
setLastServiceErrors(errors);
return errors;
}
/**
* @see com.aptana.ide.core.ILoggable#getLogger()
*/
public ILogger getLogger()
{
return this.logger;
}
/**
* @see com.aptana.ide.core.ILoggable#setLogger(com.aptana.ide.core.ILogger)
*/
public void setLogger(ILogger logger)
{
this.logger = logger;
}
/**
* @return the id
*/
public String getId()
{
return id;
}
/**
* @param id
* the id to set
*/
public void setId(String id)
{
this.id = id;
}
/**
* Clears the model this object holds
*/
public synchronized void clear()
{
// Does nothing by default
}
/**
* Get last update status
*
* @return - last status
*/
public int getLastUpdateStatus()
{
return lastUpdateStatus;
}
/**
* Gets the text content
*
* @param xpath
* @param node
* @return - text content
*/
protected String getTextContent(String xpath, Node node)
{
String text = null;
try
{
Node subNode = (Node) XPATH.evaluate(xpath, node, XPathConstants.NODE);
if (subNode != null)
{
text = subNode.getTextContent();
}
}
catch (XPathExpressionException e)
{
String message = MessageFormat.format(
Messages.getString("CoreModelObject.XPath_Error_While_Parsing"), //$NON-NLS-1$
new Object[] {
getLoggingPrefix(),
e.getMessage()
}
);
logError(message);
}
return text;
}
/**
* @see com.aptana.ide.core.model.ILocationObject#getLastServiceErrors()
*/
public ServiceErrors getLastServiceErrors()
{
return this.lastErrors;
}
/**
* Sets the last service errors
*
* @param lastErrors
*/
public void setLastServiceErrors(ServiceErrors lastErrors)
{
this.lastErrors = lastErrors;
}
}