/* * ToroDB * Copyright © 2014 8Kdata Technology (www.8kdata.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.torodb.mongodb.commands.signatures.admin; import com.eightkdata.mongowp.bson.BsonDocument; import com.eightkdata.mongowp.bson.BsonValue; import com.eightkdata.mongowp.exceptions.BadValueException; import com.eightkdata.mongowp.exceptions.FailedToParseException; import com.eightkdata.mongowp.exceptions.MongoException; import com.eightkdata.mongowp.exceptions.NoSuchKeyException; import com.eightkdata.mongowp.exceptions.TypesMismatchException; import com.eightkdata.mongowp.fields.BooleanField; import com.eightkdata.mongowp.fields.DocField; import com.eightkdata.mongowp.fields.StringField; import com.eightkdata.mongowp.server.api.MarshalException; import com.eightkdata.mongowp.server.api.impl.AbstractNotAliasableCommand; import com.eightkdata.mongowp.utils.BsonDocumentBuilder; import com.eightkdata.mongowp.utils.BsonReaderTool; import com.google.common.annotations.Beta; import com.google.common.base.Preconditions; import com.torodb.mongodb.commands.pojos.ValidationAction; import com.torodb.mongodb.commands.pojos.ValidationLevel; import com.torodb.mongodb.commands.pojos.index.IndexOptions; import com.torodb.mongodb.commands.signatures.admin.CollModCommand.CollModArgument; import com.torodb.mongodb.commands.signatures.admin.CollModCommand.CollModResult; import java.util.Iterator; import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; /** * */ @Beta public class CollModCommand extends AbstractNotAliasableCommand<CollModArgument, CollModResult> { public static final CollModCommand INSTANCE = new CollModCommand(); private CollModCommand() { super("collMod"); } @Override public Class<? extends CollModArgument> getArgClass() { return CollModArgument.class; } @Override public CollModArgument unmarshallArg(BsonDocument requestDoc) throws MongoException { return new CollModArgument.CollModArgumentBuilder(requestDoc) .build(); } @Override protected BsonDocument marshallArg(CollModArgument request) throws MarshalException { throw new UnsupportedOperationException("Not supported yet."); } @Override public Class<? extends CollModResult> getResultClass() { return CollModResult.class; } @Override public CollModResult unmarshallResult(BsonDocument resultDoc) throws BadValueException, TypesMismatchException, NoSuchKeyException, FailedToParseException, MongoException { throw new UnsupportedOperationException("Not supported yet."); } @Override public BsonDocument marshallResult(CollModResult result) throws MarshalException { return result.marshall(); } public static class CollModArgument { private static final DocField INDEX_FIELD = new DocField("index"); private static final DocField VALIDATOR_FIELD = new DocField("validator"); private static final StringField VALIDATION_LEVEL_FIELD = new StringField("validationLevel"); private static final StringField VALIDATION_ACTION_FIELD = new StringField("validationAction"); private static final DocField PIPELINE_FIELD = new DocField("pipeline"); private static final StringField VIEW_ON_FIELD = new StringField("viewOn"); private static final BooleanField USE_POWER_OF_2_SIZES_FIELD = new BooleanField( "usePowerOf2Sizes"); private static final BooleanField NO_PADDING_FIELD = new BooleanField("noPadding"); private final IndexOptions indexOptions; //TODO: Parse the validator private final BsonDocument validator; private final ValidationLevel validationLevel; private final ValidationAction validationAction; //TODO: Parse the pipeline private final BsonDocument pipeline; private final String viewOn; private final boolean usePowerOf2Sizes; private final boolean noPadding; public CollModArgument(IndexOptions indexOptions, BsonDocument validator, ValidationLevel validationLevel, ValidationAction validationAction, BsonDocument pipeline, String viewOn, boolean usePowerOf2Sizes, boolean noPadding) { this.indexOptions = indexOptions; this.validator = validator; this.validationLevel = validationLevel; this.validationAction = validationAction; this.pipeline = pipeline; this.viewOn = viewOn; this.usePowerOf2Sizes = usePowerOf2Sizes; this.noPadding = noPadding; } public IndexOptions getIndexOptions() { return indexOptions; } @Beta public BsonDocument getValidator() { return validator; } public ValidationLevel getValidationLevel() { return validationLevel; } public ValidationAction getValidationAction() { return validationAction; } @Beta public BsonDocument getPipeline() { return pipeline; } public String getViewOn() { return viewOn; } public boolean isUsePowerOf2Sizes() { return usePowerOf2Sizes; } public boolean isNoPadding() { return noPadding; } public static class CollModArgumentBuilder { private IndexOptions indexOptions; private BsonDocument validator; private ValidationLevel validationLevel; private ValidationAction validationAction; private BsonDocument pipeline; private String viewOn; private boolean usePowerOf2Sizes; private boolean noPadding; public CollModArgumentBuilder() { } public CollModArgumentBuilder(BsonDocument doc) throws TypesMismatchException, NoSuchKeyException, BadValueException { BsonDocument.Entry<?> entry; entry = doc.getEntry(INDEX_FIELD.getFieldName()); if (entry != null) { this.indexOptions = IndexOptions.unmarshall( BsonReaderTool.getDocument(entry) ); } entry = doc.getEntry(VALIDATOR_FIELD.getFieldName()); if (entry != null) { this.validator = BsonReaderTool.getDocument(entry); } entry = doc.getEntry(VALIDATION_LEVEL_FIELD.getFieldName()); if (entry != null) { this.validationLevel = ValidationLevel.parse( BsonReaderTool.getString(entry) ); } entry = doc.getEntry(VALIDATION_ACTION_FIELD.getFieldName()); if (entry != null) { this.validationAction = ValidationAction.parse( BsonReaderTool.getString(entry) ); } entry = doc.getEntry(PIPELINE_FIELD.getFieldName()); if (entry != null) { this.pipeline = BsonReaderTool.getDocument(entry); } entry = doc.getEntry(VIEW_ON_FIELD.getFieldName()); if (entry != null) { this.viewOn = BsonReaderTool.getString(entry); } entry = doc.getEntry(USE_POWER_OF_2_SIZES_FIELD.getFieldName()); if (entry != null) { this.usePowerOf2Sizes = BsonReaderTool.isPseudoTrue(entry); } entry = doc.getEntry(NO_PADDING_FIELD.getFieldName()); if (entry != null) { this.noPadding = BsonReaderTool.isPseudoTrue(entry); } } public CollModArgumentBuilder setIndexOptions(IndexOptions indexOptions) { this.indexOptions = indexOptions; return this; } public CollModArgumentBuilder setValidator(BsonDocument validator) { this.validator = validator; return this; } public CollModArgumentBuilder setValidationLevel(ValidationLevel validationLevel) { this.validationLevel = validationLevel; return this; } public CollModArgumentBuilder setPipeline(BsonDocument pipeline) { this.pipeline = pipeline; return this; } public CollModArgumentBuilder setViewOn(String viewOn) { this.viewOn = viewOn; return this; } public CollModArgumentBuilder setUsePowerOf2Sizes(boolean usePowerOf2Sizes) { this.usePowerOf2Sizes = usePowerOf2Sizes; return this; } public CollModArgumentBuilder setNoPadding(boolean noPadding) { this.noPadding = noPadding; return this; } public CollModArgument build() { return new CollModArgument(indexOptions, validator, validationLevel, validationAction, pipeline, viewOn, usePowerOf2Sizes, noPadding); } } } public static class CollModResult { private final SortedMap<String, BsonValue<?>> oldValues; private final SortedMap<String, BsonValue<?>> newValues; private CollModResult(SortedMap<String, BsonValue<?>> oldValues, SortedMap<String, BsonValue<?>> newValues) { this.oldValues = oldValues; this.newValues = newValues; } public BsonValue<?> getOldValue(String property) { return oldValues.get(property); } public BsonValue<?> getNewValue(String property) { return newValues.get(property); } public BsonDocument marshall() { BsonDocumentBuilder builder = new BsonDocumentBuilder(oldValues.size() * 2); Iterator<Entry<String, BsonValue<?>>> oldEntries = oldValues.entrySet().iterator(); Iterator<Entry<String, BsonValue<?>>> newEntries = newValues.entrySet().iterator(); while (oldEntries.hasNext()) { Entry<String, BsonValue<?>> oldEntry = oldEntries.next(); assert newEntries.hasNext() : "There are more old entries than " + "new ones. The expected key is " + oldEntry.getKey(); Entry<String, BsonValue<?>> newEntry = newEntries.next(); builder.appendUnsafe(oldEntry.getKey() + "_old", oldEntry.getValue()); builder.appendUnsafe(newEntry.getKey() + "_new", newEntry.getValue()); } assert !newEntries.hasNext() : "There are more new entries than " + "old ones. The expected key is " + newEntries.next().getKey(); return builder.build(); } public static class CollModResultBuilder { private final SortedMap<String, BsonValue<?>> oldValues = new TreeMap<>(); private final SortedMap<String, BsonValue<?>> newValues = new TreeMap<>(); private boolean used = false; public CollModResultBuilder addPropery(String propName, BsonValue<?> oldValue, BsonValue<?> newValue) { Preconditions.checkState(!used, "This builder has been used before"); oldValues.put(propName, oldValue); newValues.put(propName, newValue); return this; } public CollModResult build() { this.used = true; return new CollModResult(oldValues, newValues); } } } }