/*
* Copyright (C) 2005-2012 BetaCONCEPT Limited
*
* This file is part of Astroboa.
*
* Astroboa 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.
*
* Astroboa 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 Astroboa. If not, see <http://www.gnu.org/licenses/>.
*/
package org.betaconceptframework.astroboa.console.jsf.edit;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import javax.faces.application.FacesMessage;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.definition.ContentObjectTypeDefinition;
import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType;
import org.betaconceptframework.astroboa.api.security.CmsRole;
import org.betaconceptframework.astroboa.api.service.DefinitionService;
import org.betaconceptframework.astroboa.console.jsf.DynamicUIAreaPageComponent;
import org.betaconceptframework.astroboa.console.jsf.PageController;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.model.impl.definition.ContentObjectTypeDefinitionImpl;
import org.betaconceptframework.astroboa.security.CmsRoleAffiliationFactory;
import org.betaconceptframework.ui.jsf.utility.JSFUtilities;
import org.betaconceptframework.utility.GreekToEnglish;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.security.Identity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
@Name("contentTypeEditor")
@Scope(ScopeType.CONVERSATION)
public class ContentTypeEditor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private DefinitionService definitionService;
private PageController pageController;
private Map<String, XSDSchemaContainer> xsdSchemasPerContentType = new HashMap<String, XSDSchemaContainer>();
private String newContentTypeFilename;
private String newContentTypeSchema;
private String selectedContentTypeForEdit;
public String loadContentTypesForEdit_UIAction(){
clearXsdSchemaCache();
newContentTypeFilename = null;
newContentTypeSchema = null;
selectedContentTypeForEdit = null;
return pageController.loadPageComponentInDynamicUIArea(DynamicUIAreaPageComponent.OBJECT_TYPE_SELECTOR.getDynamicUIAreaPageComponent());
}
public boolean shouldEditContentTypeXSD(String contentType){
try{
if (contentType == null || ( ! contentType.endsWith(".xsd") && ! definitionService.hasContentObjectTypeDefinition(contentType))){
return false;
}
Object contentDefinition = retrieveFileForDefinition(contentType);
boolean contentTypeIsBuiltIn = contentDefinition != null && contentDefinition instanceof String;
if (contentTypeIsBuiltIn){
return false;
}
//Finally only user with ROLE_ADMIN can edit XSD files
return Identity.instance().hasRole(CmsRoleAffiliationFactory.INSTANCE.getCmsRoleAffiliationForActiveRepository(CmsRole.ROLE_ADMIN));
}
catch(Exception e){
logger.error(" ",e);
return false;
}
}
public void loadXSDSchemaForContentType(String contentType){
if (StringUtils.isBlank(contentType)){
return;
}
if (! xsdSchemasPerContentType.containsKey(contentType)){
try{
Object contentTypeFile = retrieveFileForDefinition(contentType);
if (contentTypeFile == null){
return;
}
XSDSchemaContainer schemaContainer = new XSDSchemaContainer();
if (contentTypeFile instanceof File){
schemaContainer.setSchema(FileUtils.readFileToString((File)contentTypeFile,"UTF-8"));
schemaContainer.setSchemaFile((File)contentTypeFile);
}
else if (contentTypeFile instanceof byte[]){
String schema = new String((byte[])contentTypeFile,"UTF-8");
schemaContainer.setSchema(schema);
}
else if (contentTypeFile instanceof String){
schemaContainer.setSchema((String) contentTypeFile);
}
xsdSchemasPerContentType.put(contentType, schemaContainer);
}
catch(Exception e){
logger.error("",e);
return;
}
}
selectedContentTypeForEdit = contentType;
}
public String saveContentType_UIAction(String contentType){
if (contentType != null){
if (xsdSchemasPerContentType.containsKey(contentType)){
XSDSchemaContainer schemaContainer = xsdSchemasPerContentType.get(contentType);
if (schemaContainer.getSchemaFile() == null){
return null;
}
if (! validateDefinition(schemaContainer.getSchemaFile().getName(), schemaContainer.getSchema(), contentType)){
return null;
}
if (schemaContainer.save()){
return finalizeSuccessfullSave(contentType, true);
}
}
else if ("NEW_CONTENT_TYPE".equals(contentType)){
if (StringUtils.isNotBlank(newContentTypeFilename) && StringUtils.isNotBlank(newContentTypeSchema)){
try{
if (! validateDefinition(newContentTypeFilename, newContentTypeSchema, newContentTypeSchema)){
return null;
}
File definitionHomeDir = new File(getDefinitionSchemaHomeDirectory());
if (definitionHomeDir.exists()){
if (! newContentTypeFilename.endsWith(".xsd")){
newContentTypeFilename += ".xsd";
}
newContentTypeFilename = GreekToEnglish.convertString(newContentTypeFilename);
String[] existingXSDs = definitionHomeDir.list();
if (existingXSDs != null && existingXSDs.length > 0){
for(String filename : existingXSDs){
if (StringUtils.equals(filename, newContentTypeFilename)){
JSFUtilities.addMessage(null, "object.type.select.content.type.exists", new String[]{newContentTypeFilename}, FacesMessage.SEVERITY_INFO);
return null;
}
}
}
File newContentTypeFile = new File(definitionHomeDir, newContentTypeFilename);
FileUtils.writeStringToFile(newContentTypeFile, newContentTypeSchema, "UTF-8");
String contentTypeToBeUsedForMessage = new String(newContentTypeFilename);
newContentTypeFilename = null;
newContentTypeSchema = null;
return finalizeSuccessfullSave(contentTypeToBeUsedForMessage, false);
}
}
catch(Exception e){
logger.error("",e);
}
}
else{
JSFUtilities.addMessage(null, "object.type.select.new.content.type.missing", null, FacesMessage.SEVERITY_WARN);
}
}
}
return null;
}
private String finalizeSuccessfullSave(String contentType, boolean searchDefinition) {
ContentObjectTypeDefinition typeDefinition = null;
if (searchDefinition){
typeDefinition = (ContentObjectTypeDefinition) definitionService.getCmsDefinition(contentType, ResourceRepresentationType.DEFINITION_INSTANCE,false);
}
String label = null;
if (typeDefinition != null && typeDefinition.getDisplayName() !=null){
label = typeDefinition.getDisplayName().getLocalizedLabelForLocale(JSFUtilities.getLocaleAsString());
}
if (label == null){
label = contentType;
}
JSFUtilities.addMessage(null, "object.type.select.table.save.content.type.success", new String[]{label}, FacesMessage.SEVERITY_INFO);
// if a type has been added or edited then remove "contentObjectTypesAsSelectItems" from page scope so that all menus that
// show the available contet types will be reloaded
Contexts.getConversationContext().remove("contentObjectTypesAsSelectItems");
Contexts.getConversationContext().flush();
return null;
}
private boolean validateDefinition(String definitionFilename, String definition, String contentType) {
try{
if (! definitionService.validateDefinintion(definition, definitionFilename)){
JSFUtilities.addMessage(null, "content.type.validate.failure", new String[]{contentType, ""}, FacesMessage.SEVERITY_WARN);
return false;
}
return true;
}
catch(Exception e){
JSFUtilities.addMessage(null, "content.type.validate.failure", new String[]{contentType, e.getMessage()}, FacesMessage.SEVERITY_WARN);
return false;
}
}
private Object retrieveFileForDefinition(String contentType) {
try{
//Domain specific content type home directory
String contentDefinitionSchemaPath = getDefinitionSchemaHomeDirectory();
if( contentType.endsWith(".xsd")){
//Special case content type represents file name
File contentTypeFile = new File(contentDefinitionSchemaPath, contentType);
if (contentTypeFile.exists()){
return contentTypeFile;
}
return null;
}
else{
ContentObjectTypeDefinition typeDefinition = (ContentObjectTypeDefinition) definitionService.getCmsDefinition(contentType, ResourceRepresentationType.DEFINITION_INSTANCE,false);
URI contentTypeFileURI = ((ContentObjectTypeDefinitionImpl)typeDefinition).getDefinitionFileURI();
if (contentTypeFileURI.getScheme() == null || ! contentTypeFileURI.getScheme().startsWith("file")){
//Probably a built in content type. Load XSD in byte array
return definitionService.getCmsDefinition(contentType, ResourceRepresentationType.XSD,true);
/*if (contentTypeFileURI.getScheme().startsWith("jar")){
return definitionService.getXMLSchemaForDefinition(contentType);
}
return null;
*/
}
File contentTypeFile = new File(contentTypeFileURI);
if (! contentTypeFile.exists() || contentTypeFile.getParentFile() == null || ! contentTypeFile.getParentFile().exists() ||
contentTypeFile.getParentFile().getAbsolutePath() == null){
//File not found. Return XSD byte array
return definitionService.getCmsDefinition(contentType, ResourceRepresentationType.XSD,true);
}
if (! StringUtils.equals(contentTypeFile.getParentFile().getAbsolutePath(), contentDefinitionSchemaPath)){
//This way it is ensured that the file is located under the expected directory
logger.error("File is there but its parent absolute path {} is not the same with definition parent directory {}",
contentTypeFile.getParentFile().getAbsolutePath(), contentDefinitionSchemaPath);
return null;
}
return contentTypeFile;
}
}
catch(Exception e){
logger.error("",e);
return null;
}
}
private String getDefinitionSchemaHomeDirectory() {
String contentDefinitionSchemaPath = AstroboaClientContextHolder.getActiveCmsRepository().getRepositoryHomeDirectory()+File.separator+
"astroboa_schemata";
return contentDefinitionSchemaPath;
}
public void setDefinitionService(DefinitionService definitionService) {
this.definitionService = definitionService;
}
public String getNewContentTypeFilename() {
return newContentTypeFilename;
}
public void setNewContentTypeFilename(String newContentTypeFilename) {
this.newContentTypeFilename = newContentTypeFilename;
}
public String getNewContentTypeSchema() {
return newContentTypeSchema;
}
public void setNewContentTypeSchema(String newContentTypeSchema) {
this.newContentTypeSchema = newContentTypeSchema;
}
public void setPageController(PageController pageController) {
this.pageController = pageController;
}
public void clearXsdSchemaCache() {
xsdSchemasPerContentType.clear();
}
public String getSelectedContentTypeForEdit() {
return selectedContentTypeForEdit;
}
public void setSelectedContentTypeForEdit(String selectedContentTypeForEdit) {
this.selectedContentTypeForEdit = selectedContentTypeForEdit;
}
public Map<String, XSDSchemaContainer> getXsdSchemasPerContentType() {
return xsdSchemasPerContentType;
}
}