/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.kie.workbench.common.screens.datamodeller.client.widgets.jpadomain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import com.google.gwt.user.client.ui.Widget;
import org.gwtbootstrap3.client.ui.constants.ButtonType;
import org.kie.workbench.common.screens.datamodeller.client.command.DataModelCommand;
import org.kie.workbench.common.screens.datamodeller.client.command.DataModelCommandBuilder;
import org.kie.workbench.common.screens.datamodeller.client.command.ValuePair;
import org.kie.workbench.common.screens.datamodeller.client.handlers.DomainHandlerRegistry;
import org.kie.workbench.common.screens.datamodeller.client.handlers.jpadomain.JPADomainHandler;
import org.kie.workbench.common.screens.datamodeller.client.handlers.jpadomain.util.SequenceGeneratorValueHandler;
import org.kie.workbench.common.screens.datamodeller.client.model.DataModelerPropertyEditorFieldInfo;
import org.kie.workbench.common.screens.datamodeller.client.resources.i18n.Constants;
import org.kie.workbench.common.screens.datamodeller.client.util.AnnotationValueHandler;
import org.kie.workbench.common.screens.datamodeller.client.util.DataModelerUtils;
import org.kie.workbench.common.screens.datamodeller.client.widgets.common.domain.ObjectEditor;
import org.kie.workbench.common.screens.datamodeller.events.DataModelerEvent;
import org.kie.workbench.common.screens.datamodeller.model.jpadomain.JPADomainAnnotations;
import org.kie.workbench.common.services.datamodeller.core.Annotation;
import org.kie.workbench.common.services.datamodeller.core.DataObject;
import org.kie.workbench.common.services.datamodeller.core.ObjectProperty;
import org.kie.workbench.common.services.datamodeller.core.impl.AnnotationImpl;
import org.uberfire.ext.properties.editor.client.fields.BooleanField;
import org.uberfire.ext.properties.editor.client.fields.TextField;
import org.uberfire.ext.properties.editor.model.PropertyEditorCategory;
import org.uberfire.ext.widgets.common.client.resources.i18n.CommonConstants;
import org.uberfire.mvp.Command;
@Dependent
public class JPADataObjectEditor
extends ObjectEditor
implements JPADataObjectEditorView.Presenter {
private static Map<String, DataModelerPropertyEditorFieldInfo> propertyEditorFields = new HashMap<String, DataModelerPropertyEditorFieldInfo>();
private JPADataObjectEditorView view;
private JPADomainHandler handler;
private static final String EOL = "</BR>";
private static final String BLANK = " ";
private static final String TWO_BLANKS = BLANK + BLANK;
@Inject
public JPADataObjectEditor( JPADataObjectEditorView view,
DomainHandlerRegistry handlerRegistry,
Event<DataModelerEvent> dataModelerEvent,
DataModelCommandBuilder commandBuilder ) {
super( handlerRegistry, dataModelerEvent, commandBuilder );
this.view = view;
view.init( this );
List<String> domainQuery = new ArrayList<String>( );
domainQuery.add( getDomainName() );
handler = (JPADomainHandler) handlerRegistry.getDomainHandlers( domainQuery ).get( 0 );
}
@PostConstruct
protected void init() {
loadPropertyEditor();
}
@Override
public Widget asWidget() {
return view.asWidget();
}
@Override
public String getName() {
return "JPA_OBJECT_EDITOR";
}
@Override
public String getDomainName() {
return JPADomainEditor.JPA_DOMAIN;
}
@Override
protected void loadDataObject( DataObject dataObject ) {
clear();
setReadonly( true );
this.dataObject = dataObject;
if ( dataObject != null ) {
updateEntityField( dataObject.getAnnotation( JPADomainAnnotations.JAVAX_PERSISTENCE_ENTITY_ANNOTATION ) );
updateTableNameField( dataObject.getAnnotation( JPADomainAnnotations.JAVAX_PERSISTENCE_TABLE_ANNOTATION ) );
updateAuditedField( dataObject.getAnnotation( JPADomainAnnotations.HIBERNATE_ENVERS_AUDITED ) );
setReadonly( getContext() == null || getContext().isReadonly() );
}
loadPropertyEditor();
}
@Override
public void onEntityFieldChange( String newValue ) {
if ( getDataObject() != null ) {
final Boolean doAdd = Boolean.parseBoolean( newValue );
if ( doAdd ) {
if ( !hasIdField( getDataObject() ) ) {
List<ObjectProperty> configurableFields = persistenceConfigurableFields( getDataObject() );
String message = buildOnSetPersistableRefactoringMessage( false, configurableFields );
view.showYesNoCancelPopup( CommonConstants.INSTANCE.Warning(),
message,
new Command() {
@Override
public void execute() {
doEntityFieldChange( doAdd, true );
}
},
Constants.INSTANCE.persistence_domain_objectEditor_add_identifier_action(),
ButtonType.PRIMARY,
new Command() {
@Override
public void execute() {
doEntityFieldChange( doAdd, false );
}
},
Constants.INSTANCE.persistence_domain_objectEditor_dont_add_identifier_action(),
ButtonType.DANGER,
new Command() {
@Override
public void execute() {
updateEntityField( null );
loadPropertyEditor();
}
},
CommonConstants.INSTANCE.Cancel(),
ButtonType.DEFAULT );
} else {
doEntityFieldChange( doAdd, false );
}
} else {
doEntityFieldChange( doAdd, false );
}
}
}
@Override
public void onTableNameChange( String newValue ) {
if ( getDataObject() != null ) {
String value = DataModelerUtils.nullTrim( newValue );
DataModelCommand command = commandBuilder.buildDataObjectAnnotationValueChangeCommand( getContext(),
getName(), getDataObject(), JPADomainAnnotations.JAVAX_PERSISTENCE_TABLE_ANNOTATION, "name", value, true );
command.execute();
}
}
@Override
public void onAuditedFieldChange( String newValue ) {
if ( getDataObject() != null ) {
Boolean doAdd = Boolean.parseBoolean( newValue );
DataModelCommand command;
if ( doAdd ) {
List<ValuePair> defaultValues = new ArrayList<>( );
defaultValues.add( new ValuePair( "targetAuditMode", "NOT_AUDITED" ) );
command = commandBuilder.buildDataObjectAddAnnotationCommand( getContext(),
getName(), getDataObject(), JPADomainAnnotations.HIBERNATE_ENVERS_AUDITED, defaultValues );
} else {
command = commandBuilder.buildDataObjectRemoveAnnotationCommand( getContext(),
getName(), getDataObject(), JPADomainAnnotations.HIBERNATE_ENVERS_AUDITED );
}
command.execute();
}
}
//convenient method for facilitating testing
protected void doEntityFieldChange( boolean isPersistable, boolean generateIdenfitier ) {
final DataModelCommand command = commandBuilder.buildDataObjectAddOrRemoveAnnotationCommand( getContext(),
getName(), getDataObject(), JPADomainAnnotations.JAVAX_PERSISTENCE_ENTITY_ANNOTATION, isPersistable );
if ( generateIdenfitier ) {
addByDefaultId( dataObject );
}
command.execute();
}
private void updateEntityField( Annotation annotation ) {
clearEntityField();
if ( annotation != null ) {
updatePropertyEditorField( JPADataObjectEditorView.ENTITY_FIELD, annotation, "true" );
}
}
private void updateTableNameField( Annotation annotation ) {
clearTableNameField();
if ( annotation != null ) {
String tableName = AnnotationValueHandler.getStringValue( annotation, "name", null );
updatePropertyEditorField( JPADataObjectEditorView.TABLE_NAME_FIELD, annotation, tableName );
}
}
private void updateAuditedField( Annotation annotation ) {
clearAuditedField();
if ( annotation != null ) {
if ( propertyEditorFields.containsKey( JPADataObjectEditorView.AUDITED_FIELD ) ) {
updatePropertyEditorField( JPADataObjectEditorView.AUDITED_FIELD, annotation, "true" );
}
}
}
protected void loadPropertyEditor() {
view.loadPropertyEditorCategories( getPropertyEditorCategories() );
}
protected List<PropertyEditorCategory> getPropertyEditorCategories() {
final List<PropertyEditorCategory> categories = new ArrayList<PropertyEditorCategory>();
PropertyEditorCategory category = new PropertyEditorCategory( getEntityCategoryName(), 1 );
categories.add( category );
category.withField( createEntityField() );
category.withField( createTableNameField() );
if ( handler.isDataObjectAuditEnabled() ) {
category.withField( createAuditedField() );
}
return categories;
}
private DataModelerPropertyEditorFieldInfo createEntityField() {
return createField( Constants.INSTANCE.persistence_domain_objectEditor_entity_field_label(),
JPADataObjectEditorView.ENTITY_FIELD,
"false",
BooleanField.class,
Constants.INSTANCE.persistence_domain_objectEditor_entity_field_help_heading(),
Constants.INSTANCE.persistence_domain_objectEditor_entity_field_help() );
}
private DataModelerPropertyEditorFieldInfo createTableNameField() {
return createField( Constants.INSTANCE.persistence_domain_objectEditor_table_field_label(),
JPADataObjectEditorView.TABLE_NAME_FIELD,
"",
TextField.class,
Constants.INSTANCE.persistence_domain_objectEditor_table_field_help_heading(),
Constants.INSTANCE.persistence_domain_objectEditor_table_field_help() );
}
private DataModelerPropertyEditorFieldInfo createAuditedField() {
return createField( Constants.INSTANCE.persistence_domain_objectEditor_audited_field_label(),
JPADataObjectEditorView.AUDITED_FIELD,
"false",
BooleanField.class,
Constants.INSTANCE.persistence_domain_objectEditor_audited_field_help_heading(),
Constants.INSTANCE.persistence_domain_objectEditor_audited_field_help() );
}
private DataModelerPropertyEditorFieldInfo createField( String label, String key, String currentStringValue, Class<?> customFieldClass ) {
return createField( label, key, currentStringValue, customFieldClass, null, null );
}
private DataModelerPropertyEditorFieldInfo createField( String label, String key, String currentStringValue, Class<?> customFieldClass, String helpHeading, String helpText ) {
DataModelerPropertyEditorFieldInfo fieldInfo = propertyEditorFields.get( key );
if ( fieldInfo == null ) {
fieldInfo = new DataModelerPropertyEditorFieldInfo( label, currentStringValue, customFieldClass );
fieldInfo.withKey( key );
if ( helpHeading != null ) {
fieldInfo.withHelpInfo( helpHeading, helpText );
}
propertyEditorFields.put( key, fieldInfo );
}
return fieldInfo;
}
@Override
public void clear() {
clearEntityField();
clearTableNameField();
clearAuditedField();
}
private void clearEntityField() {
updatePropertyEditorField( JPADataObjectEditorView.ENTITY_FIELD, null, "false" );
}
private void clearTableNameField() {
updatePropertyEditorField( JPADataObjectEditorView.TABLE_NAME_FIELD, null, "" );
}
private void clearAuditedField() {
if ( propertyEditorFields.containsKey( JPADataObjectEditorView.AUDITED_FIELD ) ) {
updatePropertyEditorField( JPADataObjectEditorView.AUDITED_FIELD, null, "false" );
}
}
private void updatePropertyEditorField( String fieldId, Annotation currentValue, String currentStringValue ) {
DataModelerPropertyEditorFieldInfo fieldInfo = propertyEditorFields.get( fieldId );
fieldInfo.setCurrentValue( currentValue );
fieldInfo.setCurrentStringValue( currentStringValue );
}
private String getEntityCategoryName() {
return Constants.INSTANCE.persistence_domain_objectEditor_entity_category();
}
private boolean hasIdField( DataObject dataObject ) {
for ( ObjectProperty objectProperty : dataObject.getProperties() ) {
if ( objectProperty.getAnnotation( JPADomainAnnotations.JAVAX_PERSISTENCE_ID_ANNOTATION ) != null ) {
return true;
}
}
return false;
}
private List<ObjectProperty> persistenceConfigurableFields( DataObject dataObject ) {
List<ObjectProperty> result = new ArrayList<ObjectProperty>( );
for ( ObjectProperty field : dataObject.getProperties() ) {
if ( DataModelerUtils.isManagedProperty( field ) && ( field.isMultiple() || !field.isBaseType() ) ) {
result.add( field );
}
}
return result;
}
private void addByDefaultId( DataObject dataObject ) {
//add the by default id field
String idFieldName = generateIdFieldName( dataObject );
commandBuilder.buildAddPropertyCommand(
getContext(),
getName(),
dataObject,
idFieldName,
null,
Long.class.getName(),
false ).execute();
ObjectProperty idField = dataObject.getProperty( idFieldName );
commandBuilder.buildFieldAnnotationAddCommand( getContext(),
getName(),
dataObject,
idField,
JPADomainAnnotations.JAVAX_PERSISTENCE_ID_ANNOTATION ).execute();
//set the by default generated value annotation.
String generatorName = dataObject.getName().toUpperCase() + "_ID_GENERATOR";
Annotation generatedValue = new AnnotationImpl( context.getAnnotationDefinition(
JPADomainAnnotations.JAVAX_PERSISTENCE_GENERATED_VALUE_ANNOTATION ) );
generatedValue.setValue( "generator", generatorName );
generatedValue.setValue( "strategy", "AUTO" );
commandBuilder.buildFieldAnnotationAddCommand( getContext(),
getName(),
dataObject,
idField,
generatedValue ).execute();
//set by default sequence generator
String sequenceName = dataObject.getName().toUpperCase() + "_ID_SEQ";
Annotation sequenceGenerator = SequenceGeneratorValueHandler.createAnnotation( generatorName, sequenceName,
context.getAnnotationDefinitions() );
commandBuilder.buildFieldAnnotationAddCommand( getContext(),
getName(),
dataObject,
idField,
sequenceGenerator ).execute();
}
private String generateIdFieldName( DataObject dataObject ) {
String id = "id";
int i = 1;
boolean generated = false;
while ( !generated ) {
if ( dataObject.getProperty( id ) == null ) {
generated = true;
} else {
id = "id"+i;
i++;
}
}
return id;
}
private String buildOnSetPersistableRefactoringMessage( boolean hasIdentifier,
List<ObjectProperty> configurableFields ) {
StringBuilder message = new StringBuilder();
message.append( Constants.INSTANCE.persistence_domain_objectEditor_on_make_persistable_message() );
message.append( EOL );
if ( !hasIdentifier ) {
message.append(
Constants.INSTANCE.persistence_domain_objectEditor_required_identifier_is_missing_message() );
}
if ( configurableFields.size() > 0 ) {
message.append( Constants.INSTANCE.persistence_domain_objectEditor_review_relationship_fields_message() );
message.append( TWO_BLANKS );
boolean isFirst = true;
for ( ObjectProperty field : configurableFields ) {
if ( !isFirst ) {
message.append( "," + TWO_BLANKS );
}
isFirst = false;
message.append(
Constants.INSTANCE.persistence_domain_objectEditor_review_relationship_field_for_review_message(
field.getName() ) );
}
}
return message.toString();
}
}