/**
Copyright (C) 2012 Delcyon, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.delcyon.capo.controller.elements;
import java.util.logging.Level;
import org.w3c.dom.Element;
import com.delcyon.capo.CapoApplication;
import com.delcyon.capo.controller.AbstractControl;
import com.delcyon.capo.controller.ControlElementProvider;
import com.delcyon.capo.controller.server.ControllerClientRequestProcessor.Preferences;
import com.delcyon.capo.resourcemanager.ResourceDescriptor;
import com.delcyon.capo.resourcemanager.ResourceParameter;
import com.delcyon.capo.resourcemanager.ResourceDescriptor.Action;
import com.delcyon.capo.resourcemanager.types.ContentMetaData;
import com.delcyon.capo.resourcemanager.types.FileResourceContentMetaData.FileAttributes;
import com.delcyon.capo.resourcemanager.types.FileResourceDescriptor;
import com.delcyon.capo.util.CommandExecution;
import com.delcyon.capo.xml.XPath;
/**
* @author jeremiah
* Appends a node to the XML
*/
@ControlElementProvider(name="setID")
public class SetIDElement extends AbstractControl
{
public enum Attributes
{
name,value
}
private static final String[] supportedNamespaces = {CapoApplication.SERVER_NAMESPACE_URI};
@Override
public Attributes[] getAttributes()
{
return Attributes.values();
}
@Override
public Attributes[] getRequiredAttributes()
{
return new Attributes[]{Attributes.name,Attributes.value};
}
@Override
public String[] getSupportedNamespaces()
{
return supportedNamespaces;
}
@Override
public Object processServerSideElement() throws Exception
{
String clientID = getParentGroup().getVarValue("clientID");
if (clientID == null)
{
throw new Exception("Cannot set ID on an un authenticated client");
}
String name = getAttributeValue(Attributes.name);
String value = getAttributeValue(Attributes.value);
if (name.isEmpty() || value.isEmpty())
{
throw new Exception("Name '"+name+"' and value '"+value+"' must be set");
}
//check and see if this is an identity push, identity information gets saved for later use
String identityControlName = CapoApplication.getConfiguration().getValue(Preferences.DEFAULT_IDENTITY_FILE);
//load the clients identity.xml file
ResourceDescriptor clientResourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(this, "clients:"+clientID+"/"+identityControlName);
ContentMetaData clientResourceMetaData = clientResourceDescriptor.getResourceMetaData(getParentGroup());
if (clientResourceMetaData.exists() == false)
{
clientResourceDescriptor.performAction(getParentGroup(), Action.CREATE);
CapoApplication.logger.log(Level.INFO,"Creating new identity document for "+clientID);
XPath.dumpNode(CapoApplication.getDefaultDocument("ids.xml"), clientResourceDescriptor.getOutputStream(getParentGroup()));
}
/*START symlink code
* java as of version 6 doesn't support symlinks, so we do most of this via the command line
*/
//get the clients directory, so we can get a simple location for it to use with symlinks
ResourceDescriptor clientDirResourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(this, "clients:"+clientID);
ContentMetaData clientDirResourceMetaData = clientDirResourceDescriptor.getResourceMetaData(getParentGroup());
String baseURI = clientDirResourceDescriptor.getResourceURI().getResourceURIString().replaceFirst("/"+clientID, "").replaceFirst("file:", "");
clientDirResourceDescriptor.release(getParentGroup());
//see if we have a place to put this kind of symlink, and if not, then create it.
ResourceDescriptor idTypeResourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(this, "clients:by-"+name);
if(idTypeResourceDescriptor.getResourceMetaData(getParentGroup()).exists() == false)
{
idTypeResourceDescriptor.performAction(getParentGroup(), Action.CREATE,new ResourceParameter(ResourceDescriptor.DefaultParameters.CONTAINER, "true"));
}
idTypeResourceDescriptor.release(getParentGroup());
//now check and see if we already have a symlink for this name value pair
ResourceDescriptor idResourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(this, "clients:by-"+name+"/"+value);
boolean createLink = false;
if(idResourceDescriptor instanceof FileResourceDescriptor)
{
//if we don't then indicate that we need to make a new one.
ContentMetaData idResourceMetaData = idResourceDescriptor.getResourceMetaData(getParentGroup());
if(idResourceMetaData.exists() == false)
{
createLink = true;
}
//if we do, verify that it points to this client, and not some other
else if(clientDirResourceMetaData.getValue(FileAttributes.canonicalPath).equals(idResourceMetaData.getValue(FileAttributes.canonicalPath)) == false)
{
//remove the old symlink, don't want to deal with unpredictable java symlink interaction, so use command line
CommandExecution commandExecution = new CommandExecution("cd "+baseURI+"; rm -f by-"+name+"/"+value,1000l);
commandExecution.executeCommand();
if(commandExecution.getExitCode() == 0)
{
CapoApplication.logger.log(Level.WARNING,"Removed incorrect link for by-"+name+"/"+value+" to "+idResourceMetaData.getValue(FileAttributes.canonicalPath));
//indicate we need to make a symlink
createLink = true;
}
}
//make a symlink using command line
if(createLink == true)
{
CommandExecution commandExecution = new CommandExecution("cd "+baseURI+"; ln -s ../"+clientID+" by-"+name+"/"+value,1000l);
commandExecution.executeCommand();
if(commandExecution.getExitCode() == 0)
{
CapoApplication.logger.log(Level.INFO,"Created link for "+clientID+" to "+idResourceDescriptor.getResourceURI().getResourceURIString());
}
}
}
//free up our last resource
idResourceDescriptor.release(getParentGroup());
Element identityDocumentElement = CapoApplication.getDocumentBuilder().parse(clientResourceDescriptor.getInputStream(getParentGroup())).getDocumentElement();
String oldMD5 = XPath.getElementMD5(identityDocumentElement);
Element idElement = (Element) XPath.selectSingleNode(identityDocumentElement, "//server:id[@name = '"+name+"']");
if (idElement != null)
{
idElement.setAttribute("value", value);
}
else
{
idElement = identityDocumentElement.getOwnerDocument().createElement("server:id");
idElement.setAttribute("name", name);
idElement.setAttribute("value", value);
identityDocumentElement.appendChild(idElement);
}
String newMD5 = XPath.getElementMD5(identityDocumentElement);
if (oldMD5.equals(newMD5) == false)
{
CapoApplication.logger.log(Level.INFO, "Updating identity document for "+clientID);
XPath.dumpNode(identityDocumentElement, clientResourceDescriptor.getOutputStream(null));
clientResourceDescriptor.getOutputStream(null).close();
}
return null;
}
}