/*
* © Copyright IBM Corp. 2010
*
* 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 com.ibm.xsp.extlib.sbt.files;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.model.DataModel;
import com.ibm.commons.util.StringUtil;
import com.ibm.sbt.services.client.ClientService;
import com.ibm.sbt.services.client.ClientServicesException;
import com.ibm.sbt.services.endpoints.Endpoint;
import com.ibm.xsp.FacesExceptionEx;
import com.ibm.xsp.component.UIFileuploadEx.UploadedFile;
import com.ibm.xsp.extlib.model.DataAccessor;
import com.ibm.xsp.extlib.model.DataAccessorModel;
import com.ibm.xsp.extlib.model.DataAccessorSource;
import com.ibm.xsp.extlib.sbt.model.RestDataBlockAccessor;
import com.ibm.xsp.extlib.sbt.model.RestObjectDataSource;
import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.ibm.xsp.http.IUploadedFile;
import com.ibm.xsp.model.DataContainer;
import com.ibm.xsp.util.FacesUtil;
/**
* File service data source.
* @author Philippe Riand
* @author Justin Murray
*/
public class FileServiceData extends RestObjectDataSource {
@Override
public DataModel getDataModel() {
return new FileServiceDataModel(this, (Container) getDataContainer());
}
private class FileServiceDataModel extends DataAccessorModel {
public FileServiceDataModel(DataAccessorSource source, Container container) {
super(source, container);
}
@Override
public String getRowId() {
Container cont = getDataContainer();
Object rowInfo = cont.getDataAccessor().get(getRowIndex());
if (rowInfo instanceof FileEntry) {
FileEntry fEntry = (FileEntry) rowInfo;
String uniqueId = fEntry.getUniqueId();
if (StringUtil.isNotEmpty(uniqueId)) {
return uniqueId;
}
}
return super.getRowId();
}
}
public static class FileServiceAccessor extends RestDataBlockAccessor {
private static final long serialVersionUID = 1L;
private Object uploadedFile;
public FileServiceAccessor() {
}
public FileServiceAccessor(FileServiceData ds) {
super(ds);
}
@Override
protected Block loadBlock(int index, int blockSize) {
String urlForLog = null;
String fileServiceName = null;
try {
Endpoint provider = findEndpointBean();
IFileType fileService = findService();
if (fileService == null) {
throw new FacesExceptionEx(null, "The file service type is not assigned (null)");
}
// Compose the URL to the service
// (delegate to the service type)
Map<String, String> params = getParameters(fileService, index, blockSize);
ClientService svc;
String serviceUrl = getServiceUrl();
if(StringUtil.isEmpty(serviceUrl)){
//TODO we need to tidy this up - the fileServiceData should not have a serviceUrl attribute - that should only be associated with the FileType
serviceUrl = fileService.getServiceUrl();
}
urlForLog = serviceUrl;
fileServiceName = fileService.getType();
// Check if rootFolder param is being used
if (getRootFolder() == null || getRootFolder().length() < 1) {
// Create the service and and read the file entries
if(StringUtil.isNotEmpty(serviceUrl)){
serviceUrl = ExtLibUtil.concatPath(serviceUrl, getCurrentDirectory(), '/');
}
svc = createService(provider, fileService, serviceUrl);
}
else {
if (getRootFolder().charAt(0) != '/') {
setRootFolder("/" + getRootFolder());
}
String root = getRootFolder();
String curr = getCurrentDirectory();
String path = "";
if (curr.length() > root.length()) {
path = curr.substring(root.length(), curr.length());
}
// Create the service and and read the file entries
svc = createService(provider, fileService, serviceUrl + root + path);
}
List<FileEntry> entries = fileService.readFileEntries(svc, this, params, serviceUrl);
FileEntry[] data = entries.toArray(new FileEntry[entries.size()]);
return new ArrayBlock(index, data);
} catch (Exception ex) {
throw new FacesExceptionEx(ex, "Error while calling the file service: {0}. Failed to access URL: {1}", fileServiceName, urlForLog);
}
}
protected IFileType findService() {
FileServiceData ds = (FileServiceData) getDataSource();
return ds.getServiceType();
}
// ---------------
public String getCurrentDirectory() {
FileServiceData ds = (FileServiceData) getDataSource();
return ds.getCurrentDirectory();
}
public boolean isRootDirectory() {
FileServiceData ds = (FileServiceData) getDataSource();
return ds.isRootDirectory();
}
public String getParentDirectory() {
FileServiceData ds = (FileServiceData) getDataSource();
return ds.getParentDirectory();
}
public String getRootFolder() {
FileServiceData ds = (FileServiceData) getDataSource();
return ds.getRootFolder();
}
public void setRootFolder(String root) {
FileServiceData ds = (FileServiceData) getDataSource();
ds.setRootFolder(root);
}
public void setCurrentDirectory(String newDirectory) {
FileServiceData ds = (FileServiceData) getDataSource();
ds.setCurrentDirectory(newDirectory);
}
public void refresh() {
FileServiceData ds = (FileServiceData) getDataSource();
ds.refresh();
}
// ---------------
protected Map<String, String> getParameters(IFileType service, int index, int blockSize) throws ClientServicesException {
Map<String, String> map = new HashMap<String, String>();
map.putAll(getUrlParameters());
service.addUrlParameters(map, index, blockSize);
return map;
}
protected ClientService createService(Endpoint endpoint, IFileType fileService, String url) throws ClientServicesException {
ClientService svc = fileService.createClientService(endpoint, url);
return svc;
}
/*
* (non-Javadoc)
*
* @see com.ibm.xsp.extlib.model.DataAccessor#deleteRow(java.lang.String)
*/
@Override
public void deleteRow(String rowId) {
Endpoint authBean = findEndpointBean();
IFileType ift = (IFileType) findService();
ift.deleteRow(this, authBean, rowId);
}
public void createFolder(String folderName) throws UnsupportedEncodingException, IOException {
Endpoint authBean = findEndpointBean();
IFileType ift = (IFileType) findService();
ift.createFolder(authBean, folderName);
}
public boolean useFolders() {
IFileType ift = (IFileType) findService();
return ift.useFolders();
}
/**
* @return the uploadedFile
*/
public Object getUploadedFile() {
return uploadedFile;
}
/**
* @param uploadedFileObj the uploadedFile to set
* @throws CloneNotSupportedException
*/
public void setUploadedFile(Object uploadedFileObj) throws CloneNotSupportedException {
if (uploadedFileObj instanceof UploadedFile) {
UploadedFile uploadedFile = (UploadedFile) uploadedFileObj;
this.uploadedFile = uploadedFile;
}
}
}
private IFileType serviceType;
private String rootFolder;
private String currentDirectory = "/";
public FileServiceData() {
}
@Override
public String getDefaultEndpoint() {
IFileType type = getServiceType();
return type!=null ? type.getDefaultEndpoint() : null;
}
public String getRootFolder() {
if (null != rootFolder) {
return rootFolder;
}
ValueBinding valueBinding = getValueBinding("rootFolder");
if (valueBinding != null) {
String value = (String) valueBinding.getValue(getFacesContext());
return value;
}
return null;
}
public void setRootFolder(String rootFolder) {
this.rootFolder = rootFolder;
}
@Override
protected RestDataBlockAccessor createAccessor() {
return new FileServiceAccessor(this);
}
public IFileType getServiceType() {
return this.serviceType;
}
public String getCurrentDirectory() {
if (null != currentDirectory) {
return currentDirectory;
}
ValueBinding valueBinding = getValueBinding("currentDirectory");
if (valueBinding != null) {
String value = (String) valueBinding.getValue(getFacesContext());
return value;
}
return "/";
}
public boolean isRootDirectory() {
// return false;
boolean result = getCurrentDirectory().equals("/") || getCurrentDirectory().equals(getRootFolder());
return result;
}
public void setServiceType(IFileType serviceType) {
this.serviceType = serviceType;
}
public void setCurrentDirectory(String newDirectory) {
this.currentDirectory = newDirectory;
}
public String getParentDirectory() {
String parentDir = this.currentDirectory;
if (parentDir != null) {
for (int pos = parentDir.length() - 1; pos >= 0; pos--) {
if (parentDir.charAt(pos) == '/') {
parentDir = parentDir.substring(0, pos);
if (parentDir.equals(""))
parentDir = "/";
return parentDir;
}
}
}
return "/";
}
@Override
public void restoreState(FacesContext _context, Object _state) {
Object _values[] = (Object[]) _state;
super.restoreState(_context, _values[0]);
this.serviceType = (IFileType) FacesUtil.objectFromSerializable(_context, getComponent(), _values[1]);
this.currentDirectory = (String) _values[2];
this.rootFolder = (String) _values[3];
}
@Override
public Object saveState(FacesContext _context) {
Object _values[] = new Object[4];
_values[0] = super.saveState(_context);
_values[1] = FacesUtil.objectToSerializable(_context, serviceType);
_values[2] = this.currentDirectory;
_values[3] = this.rootFolder;
return _values;
}
/* (non-Javadoc)
* @see com.ibm.xsp.model.AbstractDataSource#save(javax.faces.context.FacesContext, boolean)
*/
@Override
public boolean save(FacesContext context, boolean force) throws FacesExceptionEx {
DataContainer container = getDataContainer();
if(container instanceof Container){
DataAccessor accessor = ((Container)container).getDataAccessor();
if(accessor instanceof FileServiceAccessor){
UploadedFile uploadedFile = (UploadedFile)((FileServiceAccessor)accessor).getUploadedFile();
if(uploadedFile != null){
IUploadedFile file = uploadedFile.getUploadedFile();
HashMap<String, String> params = new HashMap<String, String>();
String filename = uploadedFile.getFilename();
params.put("file", filename);
if (null != file) {
File serverFile = file.getServerFile();
if (null != serverFile) {
Endpoint endpoint = ((FileServiceAccessor)accessor).findEndpointBean();
IFileType ift = (IFileType) ((FileServiceAccessor)accessor).findService();
try {
ift.uploadFile(endpoint, serverFile, this, params);
refresh();
} catch (CloneNotSupportedException e) {
throw new FacesExceptionEx(e, "Failed to upload file to {0}", endpoint.getLabel());
}
}
}
}
}
}
return super.save(context, force);
}
}