package org.orienteer.core.component.meta; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.metadata.schema.OProperty; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.metadata.schema.clusterselection.OBalancedClusterSelectionStrategy; import com.orientechnologies.orient.core.metadata.schema.clusterselection.OClusterSelectionStrategy; import com.orientechnologies.orient.core.metadata.schema.clusterselection.ODefaultClusterSelectionStrategy; import com.orientechnologies.orient.core.metadata.schema.clusterselection.ORoundRobinClusterSelectionStrategy; import com.orientechnologies.orient.core.metadata.security.ORule; import com.orientechnologies.orient.core.metadata.security.OSecurityShared; import com.orientechnologies.orient.core.record.impl.ODocument; import org.apache.wicket.Application; import org.apache.wicket.Component; import org.apache.wicket.Session; import org.apache.wicket.core.util.lang.PropertyResolver; import org.apache.wicket.core.util.lang.PropertyResolverConverter; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.markup.head.CssHeaderItem; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.EnumChoiceRenderer; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.TextArea; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.IModel; import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.request.resource.CssResourceReference; import org.apache.wicket.request.resource.ResourceReference; import org.apache.wicket.util.io.IClusterable; import org.apache.wicket.validation.IValidator; import org.apache.wicket.validation.validator.PatternValidator; import org.orienteer.core.OClassDomain; import org.orienteer.core.CustomAttribute; import org.orienteer.core.behavior.RefreshMetaContextOnChangeBehaviour; import org.orienteer.core.component.property.*; import org.orienteer.core.model.OClassTextChoiceProvider; import org.orienteer.core.model.OnCreateFieldsTextChoiceProvider; import org.wicketstuff.select2.ISelect2Theme; import org.wicketstuff.select2.Select2BootstrapTheme; import org.wicketstuff.select2.Select2MultiChoice; import ru.ydn.wicket.wicketorientdb.OrientDbWebSession; import ru.ydn.wicket.wicketorientdb.model.EnumNamingModel; import ru.ydn.wicket.wicketorientdb.model.ListOPropertiesModel; import ru.ydn.wicket.wicketorientdb.model.OClassesDataProvider; import ru.ydn.wicket.wicketorientdb.model.SimpleNamingModel; import ru.ydn.wicket.wicketorientdb.proto.OClassPrototyper; import ru.ydn.wicket.wicketorientdb.proto.OPropertyPrototyper; import ru.ydn.wicket.wicketorientdb.security.OSecurityHelper; import ru.ydn.wicket.wicketorientdb.security.OrientPermission; import ru.ydn.wicket.wicketorientdb.utils.ResourceChoiceRenderer; import ru.ydn.wicket.wicketorientdb.validation.OSchemaNamesValidator; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.regex.Pattern; /** * Meta panel for {@link OClass} * * @param <V> type of a value */ public class OClassMetaPanel<V> extends AbstractComplexModeMetaPanel<OClass, DisplayMode, String, V> implements IDisplayModeAware { public static final ISelect2Theme BOOTSTRAP_SELECT2_THEME = new FixedSelect2BootstrapTheme(); /** * Reimplementation of {@link Select2BootstrapTheme} just to have it {@link Serializable} */ public static class FixedSelect2BootstrapTheme implements ISelect2Theme, IClusterable { private static final ResourceReference CSS = new CssResourceReference(Select2BootstrapTheme.class, "/res/bootstrap/select2-bootstrap.css"); public FixedSelect2BootstrapTheme() { } @Override public void renderHead(Component component, IHeaderResponse response) { response.render(CssHeaderItem.forReference(CSS)); } @Override public String name() { return "bootstrap"; } }; public static final List<String> OCLASS_ATTRS = new ArrayList<String>(OClassPrototyper.OCLASS_ATTRS); static { //Index:OCLASS_ATTRS.indexOf(OClassPrototyper.NAME)+1 OCLASS_ATTRS.add(2, CustomAttribute.DESCRIPTION.getName()); OCLASS_ATTRS.add(CustomAttribute.DOMAIN.getName()); OCLASS_ATTRS.add(CustomAttribute.PROP_NAME.getName()); OCLASS_ATTRS.add(CustomAttribute.PROP_PARENT.getName()); OCLASS_ATTRS.add(CustomAttribute.TAB.getName()); OCLASS_ATTRS.add(CustomAttribute.SORT_BY.getName()); OCLASS_ATTRS.add(CustomAttribute.SORT_ORDER.getName()); OCLASS_ATTRS.add(CustomAttribute.SEARCH_QUERY.getName()); OCLASS_ATTRS.add(CustomAttribute.ON_CREATE_FIELDS.getName()); OCLASS_ATTRS.add(CustomAttribute.ON_CREATE_IDENTITY_TYPE.getName()); } private static final Predicate<OProperty> IS_LINK_PROPERTY = new Predicate<OProperty>() { @Override public boolean apply(OProperty input) { return input!=null?input.getType().isLink():false; } }; private static final long serialVersionUID = 1L; private static final List<String> CLUSTER_SELECTIONS = Arrays.asList(new String[]{ODefaultClusterSelectionStrategy.NAME, ORoundRobinClusterSelectionStrategy.NAME, OBalancedClusterSelectionStrategy.NAME}); private static final List<String> ON_CREATE_IDENTITY_SELECTIONS = Arrays.asList(new String[]{"user", "role"}); public OClassMetaPanel(String id, IModel<DisplayMode> modeModel, IModel<OClass> entityModel, IModel<String> criteryModel) { super(id, modeModel, entityModel, criteryModel); } @SuppressWarnings("unchecked") @Override protected V getValue(OClass entity, String critery) { CustomAttribute custom; if("clusterSelection".equals(critery)) { OClusterSelectionStrategy strategy = entity.getClusterSelection(); return (V)(strategy!=null?strategy.getName():null); } else if(OClassPrototyper.SUPER_CLASSES.equals(critery)) { List<OClass> superClasses = entity.getSuperClasses(); // Additional wrapping to ArrayList is required , because getSuperClasses return unmodifiable list return (V)(superClasses != null ? new ArrayList<OClass>(superClasses) : new ArrayList<OClass>()); } else if((CustomAttribute.ON_CREATE_FIELDS.getName().equals(critery)) && (custom = CustomAttribute.getIfExists(critery)) != null) { String onCreateFields = custom.getValue(entity); return (V)(!Strings.isNullOrEmpty(onCreateFields) ? Lists.newArrayList(onCreateFields.split(",")) : new ArrayList<String>()); } else if((custom = CustomAttribute.getIfExists(critery))!=null) { return custom.getValue(entity); } else { return (V)PropertyResolver.getValue(critery, entity); } } @Override protected void setValue(OClass entity, String critery, V value) { ODatabaseDocument db = OrientDbWebSession.get().getDatabase(); db.commit(); try { CustomAttribute custom; if(OClassPrototyper.CLUSTER_SELECTION.equals(critery)) { if(value!=null) entity.setClusterSelection(value.toString()); } else if((CustomAttribute.ON_CREATE_FIELDS.getName().equals(critery)) && (custom = CustomAttribute.getIfExists(critery)) != null) { custom.setValue(entity, value!=null?Joiner.on(",").join((List<String>) value):null); } else if((custom = CustomAttribute.getIfExists(critery))!=null) { custom.setValue(entity, value); } else if (OClassPrototyper.SUPER_CLASSES.equals(critery)) { if(value!=null) entity.setSuperClasses((List<OClass>) value); } else { PropertyResolver.setValue(critery, entity, value, new PropertyResolverConverter(Application.get().getConverterLocator(), Session.get().getLocale())); } } finally { db.begin(); } } @SuppressWarnings("unchecked") @Override protected Component resolveComponent(String id, DisplayMode mode, String critery) { if(DisplayMode.EDIT.equals(mode) && !OSecurityHelper.isAllowed(ORule.ResourceGeneric.SCHEMA, null, OrientPermission.UPDATE)) { mode = DisplayMode.VIEW; } if(DisplayMode.VIEW.equals(mode)) { if(CustomAttribute.match(critery, CustomAttribute.PROP_NAME, CustomAttribute.PROP_PARENT, CustomAttribute.SORT_BY)) { return new OPropertyViewPanel(id, (IModel<OProperty>)getModel()); } else if(OClassPrototyper.SUPER_CLASSES.equals(critery)) { return new MultipleOClassesViewPanel(id, (IModel<List<OClass>>)getModel()); } else if(OClassPrototyper.ABSTRACT.equals(critery) || OClassPrototyper.STRICT_MODE.equals(critery)) { return new BooleanViewPanel(id, (IModel<Boolean>)getModel()).setHideIfFalse(true); } else if(CustomAttribute.match(critery, CustomAttribute.SORT_ORDER)) { return new Label(id, new StringResourceModel("sortorder.${}", getModel())); } else if(CustomAttribute.match(critery, CustomAttribute.DOMAIN)) { return new Label(id, new EnumNamingModel<OClassDomain>((IModel<OClassDomain>)getModel())); } else { return new Label(id, getModel()); } } else if(DisplayMode.EDIT.equals(mode)) { if(OClassPrototyper.NAME.equals(critery) || OClassPrototyper.SHORT_NAME.equals(critery)) { FormComponent<V> ret = new TextField<V>(id, getModel()).setType(String.class) .add((IValidator<V>)OSchemaNamesValidator.CLASS_NAME_VALIDATOR); if(OClassPrototyper.NAME.equals(critery)) ret.setRequired(true); return ret; } else if(OClassPrototyper.ABSTRACT.equals(critery) || OClassPrototyper.STRICT_MODE.equals(critery)) { return new BooleanEditPanel(id, (IModel<Boolean>)getModel()); } else if(OClassPrototyper.OVER_SIZE.equals(critery)) { return new TextField<V>(id, getModel()).setType(Float.class); } else if(OClassPrototyper.SUPER_CLASSES.equals(critery)) { Select2MultiChoice choice = new Select2MultiChoice<OClass>(id, (IModel<Collection<OClass>>)getModel(), OClassTextChoiceProvider.INSTANCE); choice.add(new RefreshMetaContextOnChangeBehaviour()); choice.getSettings().setCloseOnSelect(true).setTheme(BOOTSTRAP_SELECT2_THEME); return choice; } else if(OClassPrototyper.CLUSTER_SELECTION.equals(critery)) { return new DropDownChoice<String>(id, (IModel<String>)getModel(), CLUSTER_SELECTIONS); } else if(CustomAttribute.match(critery, CustomAttribute.PROP_NAME)) { return new DropDownChoice<OProperty>(id, (IModel<OProperty>)getModel(), new ListOPropertiesModel(getEntityModel(), null)).setNullValid(true); } else if(CustomAttribute.match(critery, CustomAttribute.PROP_PARENT)) { return new DropDownChoice<OProperty>(id, (IModel<OProperty>)getModel(), new ListOPropertiesModel(getEntityModel(), null) { @Override protected Predicate<? super OProperty> getFilterPredicate() { return IS_LINK_PROPERTY; } }).setNullValid(true); } else if(CustomAttribute.match(critery, CustomAttribute.SORT_BY)) { return new DropDownChoice<OProperty>(id, (IModel<OProperty>)getModel(), new ListOPropertiesModel(getEntityModel(), null)).setNullValid(true); } else if(CustomAttribute.match(critery, CustomAttribute.SORT_ORDER)) { return new DropDownChoice<Boolean>(id, (IModel<Boolean>)getModel(), Arrays.asList(true, false), new ResourceChoiceRenderer<>("sortorder")).setNullValid(true); } else if(CustomAttribute.match(critery,CustomAttribute.DESCRIPTION)) { return new TextArea<V>(id, getModel()); } else if(CustomAttribute.match(critery, CustomAttribute.SEARCH_QUERY)) { return new TextArea<String>(id, (IModel<String>)getModel()) .add(new PatternValidator("^(select|where)\\s.*", Pattern.CASE_INSENSITIVE)); } else if (CustomAttribute.match(critery,CustomAttribute.TAB)) { return new TextField<V>(id,getModel()); } else if(CustomAttribute.match(critery, CustomAttribute.ON_CREATE_FIELDS)) { Select2MultiChoice<String> choice = new Select2MultiChoice<String>(id, (IModel<Collection<String>>)getModel(), OnCreateFieldsTextChoiceProvider.INSTANCE); choice.getSettings().setCloseOnSelect(true).setTheme(BOOTSTRAP_SELECT2_THEME); return choice; } else if(CustomAttribute.match(critery, CustomAttribute.ON_CREATE_IDENTITY_TYPE)) { return new DropDownChoice<String>(id, (IModel<String>)getModel(), ON_CREATE_IDENTITY_SELECTIONS).setNullValid(true); } else if(CustomAttribute.match(critery, CustomAttribute.DOMAIN)) { return new DropDownChoice<OClassDomain>(id, (IModel<OClassDomain>)getModel(), Arrays.asList(OClassDomain.values()), new EnumChoiceRenderer<OClassDomain>()); } else { return new Label(id, getModel()); } } else return null; } @Override protected void onConfigure() { super.onConfigure(); String critery = getPropertyObject(); if(OClassPrototyper.SUPER_CLASSES.equals(critery)) { Collection<OClass> superClasses = (Collection<OClass>)getEnteredValue(); AbstractMetaPanel<OClass, String, ?> onCreateFieldsPanel = getMetaComponent(CustomAttribute.ON_CREATE_FIELDS.getName()); AbstractMetaPanel<OClass, String, ?> onCreateIdentityTypePanel = getMetaComponent(CustomAttribute.ON_CREATE_IDENTITY_TYPE.getName()); if(onCreateFieldsPanel!=null || onCreateIdentityTypePanel!=null) { boolean visibility = false; for(OClass superClass : superClasses) { if(visibility = superClass.isSubClassOf(OSecurityShared.RESTRICTED_CLASSNAME)) break; } if(onCreateFieldsPanel!=null) onCreateFieldsPanel.setVisibilityAllowed(visibility); if(onCreateIdentityTypePanel!=null) onCreateIdentityTypePanel.setVisibilityAllowed(visibility); } } } @Override public IModel<String> newLabelModel() { return new SimpleNamingModel<String>("class", getPropertyModel()); } }