/*
* Copyright (c) 2010-2013 Evolveum
*
* 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.evolveum.midpoint.web.component.wizard.resource.component;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl;
import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.model.NonEmptyLoadableModel;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.AjaxButton;
import com.evolveum.midpoint.web.component.data.BoxedTablePanel;
import com.evolveum.midpoint.web.component.data.column.CheckBoxColumn;
import com.evolveum.midpoint.web.component.data.paging.NavigatorPanel;
import com.evolveum.midpoint.web.component.util.ListDataProvider;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.component.wizard.resource.dto.AttributeDto;
import com.evolveum.midpoint.web.component.wizard.resource.dto.ObjectClassDataProvider;
import com.evolveum.midpoint.web.component.wizard.resource.dto.ObjectClassDetailsDto;
import com.evolveum.midpoint.web.component.wizard.resource.dto.ObjectClassDto;
import com.evolveum.midpoint.web.page.admin.resources.PageResourceWizard;
import com.evolveum.midpoint.web.page.admin.resources.PageResources;
import com.evolveum.midpoint.web.session.UserProfileStorage;
import com.evolveum.midpoint.web.util.InfoTooltipBehavior;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author lazyman
*/
public class SchemaListPanel extends BasePanel<PrismObject<ResourceType>> {
private static final Trace LOGGER = TraceManager.getTrace(SchemaListPanel.class);
private static final String ID_TABLE_BODY = "tableBody";
private static final String ID_OBJECT_CLASS = "objectClass";
private static final String ID_OBJECT_CLASS_LIST = "objectClassList";
private static final String ID_CLASS_LINK = "classLink";
private static final String ID_LABEL = "label";
private static final String ID_CLEAR_SEARCH = "clearSearch";
private static final String ID_ATTRIBUTE_TABLE = "attributeTable";
private static final String ID_NAVIGATOR = "objectClassNavigator";
private static final String ID_OBJECT_CLASS_INFO_CONTAINER = "objectClassInfoContainer";
private static final String ID_OBJECT_CLASS_INFO_COLUMN = "objectClassInfoColumn";
private static final String ID_DETAILS_PANEL = "detailsPanel";
private static final String ID_DETAILS_DISPLAY_NAME = "displayName";
private static final String ID_DETAILS_DESCRIPTION = "description";
private static final String ID_DETAILS_KIND = "kind";
private static final String ID_DETAILS_INTENT = "intent";
private static final String ID_DETAILS_NATIVE_OBJECT_CLASS = "nativeObjectClass";
private static final String ID_DETAILS_DEFAULT = "isDefault";
private static final String ID_T_KIND = "kindTooltip";
private static final String ID_T_INTENT = "intentTooltip";
private static final String ID_T_NATIVE_OBJECT_CLASS = "nativeObjectClassTooltip";
private static final String ID_T_DEFAULT = "isDefaultTooltip";
@NotNull private final NonEmptyLoadableModel<List<ObjectClassDto>> allClasses;
@NotNull private final NonEmptyLoadableModel<ObjectClassDetailsDto> detailsModel;
@NotNull private final NonEmptyLoadableModel<List<AttributeDto>> attributeModel;
public SchemaListPanel(String id, IModel<PrismObject<ResourceType>> model, PageResourceWizard parentPage) {
super(id, model);
allClasses = new NonEmptyLoadableModel<List<ObjectClassDto>>(false) {
@Override @NotNull
protected List<ObjectClassDto> load() {
return loadAllClasses();
}
};
parentPage.registerDependentModel(allClasses);
attributeModel = new NonEmptyLoadableModel<List<AttributeDto>>(false) {
@Override @NotNull
protected List<AttributeDto> load() {
return loadAttributes();
}
};
parentPage.registerDependentModel(attributeModel);
detailsModel = new NonEmptyLoadableModel<ObjectClassDetailsDto>(true) {
@Override @NotNull
protected ObjectClassDetailsDto load() {
return loadDetails();
}
};
parentPage.registerDependentModel(detailsModel);
initLayout();
}
protected void initLayout() {
final ObjectClassDataProvider dataProvider = new ObjectClassDataProvider(allClasses);
TextField objectClass = new TextField<>(ID_OBJECT_CLASS, new Model<>());
objectClass.setOutputMarkupId(true);
objectClass.add(new AjaxFormComponentUpdatingBehavior("keyup") {
@Override
protected void onUpdate(AjaxRequestTarget target) {
updateSearchPerformed(target, dataProvider);
}
});
add(objectClass);
AjaxButton clearSearch = new AjaxButton(ID_CLEAR_SEARCH) {
@Override
public void onClick(AjaxRequestTarget target) {
clearSearchPerformed(target, dataProvider);
}
};
add(clearSearch);
WebMarkupContainer tableBody = new WebMarkupContainer(ID_TABLE_BODY);
tableBody.setOutputMarkupId(true);
add(tableBody);
DataView<ObjectClassDto> objectClassDataView = new DataView<ObjectClassDto>(ID_OBJECT_CLASS_LIST, dataProvider,
UserProfileStorage.DEFAULT_PAGING_SIZE) {
@Override
protected void populateItem(final Item<ObjectClassDto> item) {
AjaxLink link = new AjaxLink(ID_CLASS_LINK) {
@Override
public void onClick(AjaxRequestTarget target) {
objectClassClickPerformed(target, item.getModelObject());
}
};
item.add(link);
Label label = new Label(ID_LABEL, new PropertyModel<>(item.getModel(), ObjectClassDto.F_DISPLAY_NAME));
link.add(label);
item.add(AttributeModifier.replace("class", new AbstractReadOnlyModel<Object>() {
@Override
public Object getObject() {
return item.getModelObject().isSelected() ? "success" : null;
}
}));
}
};
tableBody.add(objectClassDataView);
NavigatorPanel objectClassNavigator = new NavigatorPanel(ID_NAVIGATOR, objectClassDataView, true);
objectClassNavigator.setOutputMarkupId(true);
objectClassNavigator.setOutputMarkupPlaceholderTag(true);
add(objectClassNavigator);
WebMarkupContainer objectClassInfoContainer = new WebMarkupContainer(ID_OBJECT_CLASS_INFO_CONTAINER);
objectClassInfoContainer.setOutputMarkupId(true);
add(objectClassInfoContainer);
WebMarkupContainer objectClassInfoColumn = new WebMarkupContainer(ID_OBJECT_CLASS_INFO_COLUMN);
objectClassInfoColumn.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return getSelectedObjectClass() != null;
}
});
objectClassInfoContainer.add(objectClassInfoColumn);
initDetailsPanel(objectClassInfoColumn);
ListDataProvider<AttributeDto> attributeProvider = new ListDataProvider<>(this, attributeModel, true);
attributeProvider.setSort(AttributeDto.F_DISPLAY_ORDER, SortOrder.ASCENDING);
BoxedTablePanel<AttributeDto> attributeTable = new BoxedTablePanel<>(ID_ATTRIBUTE_TABLE, attributeProvider, initColumns());
attributeTable.setOutputMarkupId(true);
attributeTable.setItemsPerPage(UserProfileStorage.DEFAULT_PAGING_SIZE);
attributeTable.setShowPaging(true);
objectClassInfoColumn.add(attributeTable);
}
private void initDetailsPanel(WebMarkupContainer parent) {
WebMarkupContainer detailsContainer = new WebMarkupContainer(ID_DETAILS_PANEL);
detailsContainer.setOutputMarkupId(true);
detailsContainer.setOutputMarkupPlaceholderTag(true);
parent.add(detailsContainer);
Label displayName = new Label(ID_DETAILS_DISPLAY_NAME, new PropertyModel<String>(detailsModel, ObjectClassDetailsDto.F_DISPLAY_NAME));
detailsContainer.add(displayName);
Label description = new Label(ID_DETAILS_DESCRIPTION, new PropertyModel<String>(detailsModel, ObjectClassDetailsDto.F_DESCRIPTION));
detailsContainer.add(description);
Label kind = new Label(ID_DETAILS_KIND, new PropertyModel<String>(detailsModel, ObjectClassDetailsDto.F_KIND));
detailsContainer.add(kind);
Label intent = new Label(ID_DETAILS_INTENT, new PropertyModel<String>(detailsModel, ObjectClassDetailsDto.F_INTENT));
detailsContainer.add(intent);
Label nativeObjectClass = new Label(ID_DETAILS_NATIVE_OBJECT_CLASS, new PropertyModel<String>(detailsModel, ObjectClassDetailsDto.F_NATIVE_OBJECT_CLASS));
detailsContainer.add(nativeObjectClass);
CheckBox isDefault = new CheckBox(ID_DETAILS_DEFAULT, new PropertyModel<Boolean>(detailsModel, ObjectClassDetailsDto.F_IS_DEFAULT));
isDefault.setEnabled(false);
detailsContainer.add(isDefault);
Label kindTooltip = new Label(ID_T_KIND);
kindTooltip.add(new InfoTooltipBehavior());
detailsContainer.add(kindTooltip);
Label intentTooltip = new Label(ID_T_INTENT);
intentTooltip.add(new InfoTooltipBehavior());
detailsContainer.add(intentTooltip);
Label nativeObjClassTooltip = new Label(ID_T_NATIVE_OBJECT_CLASS);
nativeObjClassTooltip.add(new InfoTooltipBehavior());
detailsContainer.add(nativeObjClassTooltip);
Label defaultTooltip = new Label(ID_T_DEFAULT);
defaultTooltip.add(new InfoTooltipBehavior());
detailsContainer.add(defaultTooltip);
}
private List<IColumn<AttributeDto, String>> initColumns() {
List<IColumn<AttributeDto, String>> columns = new ArrayList<>();
columns.add(new PropertyColumn<AttributeDto, String>(createStringResource("SchemaListPanel.name"), AttributeDto.F_NAME, AttributeDto.F_NAME));
columns.add(new PropertyColumn<AttributeDto, String>(createStringResource("SchemaListPanel.displayName"), AttributeDto.F_DISPLAY_NAME));
columns.add(new PropertyColumn<AttributeDto, String>(createStringResource("SchemaListPanel.nativeAttributeName"), AttributeDto.F_NATIVE_ATTRIBUTE_NAME, AttributeDto.F_NATIVE_ATTRIBUTE_NAME));
columns.add(new PropertyColumn<AttributeDto, String>(createStringResource("SchemaListPanel.minMax"), AttributeDto.F_MIN_MAX_OCCURS));
columns.add(new PropertyColumn<AttributeDto, String>(createStringResource("SchemaListPanel.displayOrder"), AttributeDto.F_DISPLAY_ORDER, AttributeDto.F_DISPLAY_ORDER));
CheckBoxColumn<AttributeDto> check = new CheckBoxColumn<>(createStringResource("SchemaListPanel.returnedByDefault"), AttributeDto.F_RETURNED_BY_DEFAULT);
check.setEnabled(false);
columns.add(check);
return columns;
}
@SuppressWarnings("unchecked")
private TextField<String> getObjectClassText() {
return (TextField<String>) get(ID_OBJECT_CLASS);
}
private void updateSearchPerformed(AjaxRequestTarget target, ObjectClassDataProvider dataProvider) {
dataProvider.setFilter(getObjectClassText().getModelObject());
target.add(get(ID_TABLE_BODY), get(ID_NAVIGATOR), get(ID_OBJECT_CLASS_INFO_CONTAINER));
}
private void clearSearchPerformed(AjaxRequestTarget target, ObjectClassDataProvider dataProvider) {
getObjectClassText().setModelObject(null);
target.add(getObjectClassText());
updateSearchPerformed(target, dataProvider);
}
private void objectClassClickPerformed(AjaxRequestTarget target, ObjectClassDto dto) {
for (ObjectClassDto o : allClasses.getObject()) {
o.setSelected(false);
}
dto.setSelected(true);
attributeModel.reset();
detailsModel.reset();
target.add(get(ID_TABLE_BODY), get(ID_OBJECT_CLASS_INFO_CONTAINER));
}
private List<AttributeDto> loadAttributes() {
List<AttributeDto> list = new ArrayList<>();
ObjectClassDto selected = getSelectedObjectClass();
if (selected == null) {
return list;
}
for (ResourceAttributeDefinition def : selected.getDefinition().getAttributeDefinitions()) {
list.add(new AttributeDto(def));
}
return list;
}
@Nullable
private ObjectClassDto getSelectedObjectClass() {
for (ObjectClassDto o : allClasses.getObject()) {
if (o.isSelected()) {
return o;
}
}
return null;
}
private ObjectClassDetailsDto loadDetails() {
ObjectClassDto selected = getSelectedObjectClass();
if (selected == null){
return new ObjectClassDetailsDto(null);
}
return new ObjectClassDetailsDto(selected.getDefinition());
}
private List<ObjectClassDto> loadAllClasses() {
List<ObjectClassDto> list = new ArrayList<>();
RefinedResourceSchema schema = loadResourceSchema();
if (schema == null) {
return list;
}
for(RefinedObjectClassDefinition definition: schema.getRefinedDefinitions()){
list.add(new ObjectClassDto(definition));
}
Collections.sort(list);
return list;
}
private RefinedResourceSchema loadResourceSchema() {
PrismObject<ResourceType> resource = getModel().getObject();
try {
Element xsdSchema = ResourceTypeUtil.getResourceXsdSchema(resource);
if (xsdSchema == null) {
return null;
}
return RefinedResourceSchemaImpl.getRefinedSchema(resource, getPageBase().getPrismContext());
} catch (SchemaException|RuntimeException ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't parse resource schema.", ex);
getSession().error(getString("SchemaListPanel.message.couldntParseSchema") + " " + ex.getMessage());
throw new RestartResponseException(PageResources.class);
}
}
}