diff --git a/common/src/main/java/org/apache/sqoop/model/MForm.java b/common/src/main/java/org/apache/sqoop/model/MForm.java index 515bf5e0..a55fe65b 100644 --- a/common/src/main/java/org/apache/sqoop/model/MForm.java +++ b/common/src/main/java/org/apache/sqoop/model/MForm.java @@ -24,7 +24,7 @@ * input gathering process to be broken down into multiple steps that can be * then paged through by the user interface. */ -public final class MForm extends MNamedElement { +public final class MForm extends MValidatedElement { private final List> inputs; diff --git a/common/src/main/java/org/apache/sqoop/model/MInput.java b/common/src/main/java/org/apache/sqoop/model/MInput.java index 3171f8ca..ec7cc2b8 100644 --- a/common/src/main/java/org/apache/sqoop/model/MInput.java +++ b/common/src/main/java/org/apache/sqoop/model/MInput.java @@ -22,7 +22,7 @@ * or a job object. * @param the value type associated with this parameter */ -public abstract class MInput extends MNamedElement { +public abstract class MInput extends MValidatedElement { private T value; protected MInput(String name) { diff --git a/common/src/main/java/org/apache/sqoop/model/MNamedElement.java b/common/src/main/java/org/apache/sqoop/model/MNamedElement.java index 0f063f77..e67a78ca 100644 --- a/common/src/main/java/org/apache/sqoop/model/MNamedElement.java +++ b/common/src/main/java/org/apache/sqoop/model/MNamedElement.java @@ -28,8 +28,6 @@ public abstract class MNamedElement extends MPersistableEntity { private final String labelKey; private final String helpKey; - private String errorMessage; - protected MNamedElement(String name) { this.name = name; @@ -58,19 +56,5 @@ public String getHelpKey() { return helpKey; } - /** - * @param errMsg any error message associated with this parameter - */ - public void setErrorMessage(String errMsg) { - this.errorMessage = errMsg; - } - - /** - * @return any error message associated with this parameter - */ - public String getErrorMessage() { - return this.errorMessage; - } - public abstract String toString(); } diff --git a/common/src/main/java/org/apache/sqoop/model/MValidatedElement.java b/common/src/main/java/org/apache/sqoop/model/MValidatedElement.java new file mode 100644 index 00000000..a0c5074e --- /dev/null +++ b/common/src/main/java/org/apache/sqoop/model/MValidatedElement.java @@ -0,0 +1,150 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.sqoop.model; + +/** + * Element that can be validated for correctness. + * + * Two severity levels are supported at the moment - warning and error. + * + * Warning: + * Warning is something suspicious, potentially wrong but something that + * can be ignored. For example in case of JDBC URL element, warning would + * be if specified host is not responding - it's warning because specified + * URL might be wrong. However at the same time URL might be right as only + * target host might be down. + * + * Error: + * Error represents unacceptable element content. For example in case of JDBC + * URL path, error would be empty element or element containing invalid URL. + */ +abstract public class MValidatedElement extends MNamedElement { + + /** + * Different levels of validation severity. + */ + public enum Severity { + /** + * Everything is fine, no issues with this element. + */ + OK, + + /** + * Warning is suspicious content of the element. + */ + WARNING, + + /** + * Error is incorrect, unacceptable content of the element. + */ + ERROR, + } + + /** + * Validation message. + * + * One element can have only one message regardless of the type. + */ + private String validationMessage; + + /** + * Severity of the message. + */ + private Severity validationSeverity; + + public MValidatedElement(String name) { + super(name); + // Everything is fine by default + this.validationSeverity = Severity.OK; + } + + /** + * Set validation message and given severity. + * + * @param severity Message severity + * @param msg Message itself + */ + public void setValidationMessage(Severity severity, String msg) { + this.validationMessage = msg; + this.validationSeverity = severity; + } + + /** + * Return validation message for given severity. + * + * Return either associated message for given severity or null in case + * that there is no message with given severity. + * + * @param severity Message severity + */ + public String getValidationMessage(Severity severity) { + return (validationSeverity == severity) ? validationMessage : null; + } + + /** + * Return validation message. + * + * Return current validation message. + */ + public String getValidationMessage() { + return validationMessage; + } + + /** + * Return message severity. + */ + public Severity getValidationSeverity() { + return validationSeverity; + } + + /** + * Set error message for this element. + * + * @param errMsg Error message + */ + public void setErrorMessage(String errMsg) { + setValidationMessage(Severity.ERROR, errMsg); + } + + /** + * Return error message associated with this element. + * + * @return Error message + */ + public String getErrorMessage() { + return getValidationMessage(Severity.ERROR); + } + + /** + * Set warning message for this element. + * + * @param warnMsg Warning message + */ + public void setWarningMessage(String warnMsg) { + setValidationMessage(Severity.WARNING, warnMsg); + } + + /** + * Retrieve warning message associated with this element. + * @return + */ + public String getWarningMessage() { + return getValidationMessage(Severity.WARNING); + } + +} diff --git a/connector/connector-generic-jdbc/src/main/java/org/apache/sqoop/connector/jdbc/GenericJdbcConnector.java b/connector/connector-generic-jdbc/src/main/java/org/apache/sqoop/connector/jdbc/GenericJdbcConnector.java index 700f7ec6..1655da9b 100644 --- a/connector/connector-generic-jdbc/src/main/java/org/apache/sqoop/connector/jdbc/GenericJdbcConnector.java +++ b/connector/connector-generic-jdbc/src/main/java/org/apache/sqoop/connector/jdbc/GenericJdbcConnector.java @@ -32,6 +32,8 @@ import org.apache.sqoop.model.MMapInput; import org.apache.sqoop.model.MStringInput; import org.apache.sqoop.connector.spi.SqoopConnector; +import org.apache.sqoop.validation.Validator; + import static org.apache.sqoop.connector.jdbc.GenericJdbcConnectorConstants.*; @@ -118,4 +120,9 @@ public Exporter getExporter() { return EXPORTER; } + @Override + public Validator getValidator() { + return new Validator(); + } + } diff --git a/connector/connector-mysql-jdbc/src/main/java/org/apache/sqoop/connector/mysqljdbc/MySqlJdbcConnector.java b/connector/connector-mysql-jdbc/src/main/java/org/apache/sqoop/connector/mysqljdbc/MySqlJdbcConnector.java index f4c3c898..aa22fcc3 100644 --- a/connector/connector-mysql-jdbc/src/main/java/org/apache/sqoop/connector/mysqljdbc/MySqlJdbcConnector.java +++ b/connector/connector-mysql-jdbc/src/main/java/org/apache/sqoop/connector/mysqljdbc/MySqlJdbcConnector.java @@ -28,6 +28,7 @@ import org.apache.sqoop.model.MForm; import org.apache.sqoop.connector.spi.SqoopConnector; import org.apache.sqoop.model.MJobForms; +import org.apache.sqoop.validation.Validator; public class MySqlJdbcConnector implements SqoopConnector { @@ -61,4 +62,9 @@ public Exporter getExporter() { // TODO Auto-generated method stub return null; } + + @Override + public Validator getValidator() { + return new Validator(); + } } diff --git a/spi/src/main/java/org/apache/sqoop/connector/spi/SqoopConnector.java b/spi/src/main/java/org/apache/sqoop/connector/spi/SqoopConnector.java index 42c26625..b452bc3f 100644 --- a/spi/src/main/java/org/apache/sqoop/connector/spi/SqoopConnector.java +++ b/spi/src/main/java/org/apache/sqoop/connector/spi/SqoopConnector.java @@ -25,6 +25,7 @@ import org.apache.sqoop.job.etl.Importer; import org.apache.sqoop.model.MJobForms; import org.apache.sqoop.model.MConnectionForms; +import org.apache.sqoop.validation.Validator; /** * Service provider interface for Sqoop Connectors. @@ -57,4 +58,13 @@ public interface SqoopConnector { */ public Exporter getExporter(); + /** + * Returns validation object that Sqoop framework can use to validate user + * supplied forms before accepting them. This object will be used both for + * connection and job forms. + * + * @return Validator object + */ + public Validator getValidator(); + } diff --git a/spi/src/main/java/org/apache/sqoop/validation/Status.java b/spi/src/main/java/org/apache/sqoop/validation/Status.java new file mode 100644 index 00000000..2c96e4b6 --- /dev/null +++ b/spi/src/main/java/org/apache/sqoop/validation/Status.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.sqoop.validation; + +/** + * Status modes of a validation process. + */ +public enum Status { + /** + * Everything is correct. + * + * There are no issues, no warnings, nothing. + */ + FINE, + + /** + * Validated entity is correct enough to be processed. + * + * There might be some warnings, but no errors. It should be safe + * to proceed with processing. + */ + ACCEPTABLE, + + /** + * There are serious issues with validated entity. + * + * We can't proceed until reported issues will be resolved. + */ + UNACCEPTABLE, +} diff --git a/spi/src/main/java/org/apache/sqoop/validation/Validator.java b/spi/src/main/java/org/apache/sqoop/validation/Validator.java new file mode 100644 index 00000000..4da5e4a7 --- /dev/null +++ b/spi/src/main/java/org/apache/sqoop/validation/Validator.java @@ -0,0 +1,114 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.sqoop.validation; + +import org.apache.sqoop.model.MConnectionForms; +import org.apache.sqoop.model.MForm; +import org.apache.sqoop.model.MJob; +import org.apache.sqoop.model.MJobForms; + +import java.util.List; + +/** + * Connection and job metadata validator. + * + * This class should be extended by connector to provide form validation for + * connection and job forms. All methods are returning only validation Status. + * List of error and warning messages is directly updated in given structures. + * You can use methods getErrorMessage and getWarningMessage to retrieve them + * or setErrorMessage and setWarningMessage to set them. + * + * There are two major use cases of this class - simple and advanced. In simple + * mode connector developer should override method validate(MForm). This method + * will get exactly one form for validation at the time. All other methods in + * default implementation will eventually delegate call to this method. There + * is no implicit way how to distinguish between connection and job form or how + * to reference different forms. + * + * In advance usage user should override methods validate(MConnectionForms) and + * validate(MJobForms). Both methods will be called with all form gathered so far + * and connector developer might use information from all forms to do cross + * form validations. + */ +public class Validator { + + /** + * Validate one single form. + * + * @param form Form to be validated + * @return Validation status + */ + public Status validate(MForm form) { + return Status.FINE; + } + + /** + * Internal method used to validate arbitrary list of forms. + * + * It's delegating validation to validate(MForm) method. Return + * status will be the highest defined in Status enumeration (e.g. the worst). + * + * @param forms List of forms to be validated + * @return Validation status + */ + protected Status validate(List forms) { + Status finalStatus = Status.FINE; + for (MForm form : forms) { + Status status = validate(form); + + if ( finalStatus.compareTo(status) > 0 ) { + finalStatus = status; + } + } + + return finalStatus; + } + + /** + * Validate connection forms. + * + * This method will be called when user will try to create new connection + * in the system. It must return FINE or ACCEPTABLE in order to proceed and + * save the job in metadata repository. + * + * Default implementation will delegate the task to validate(MForm). + * + * @param connection Connection to be validated + * @return Validation status + */ + public Status validate(MConnectionForms connection) { + return validate(connection.getForms()); + } + + /** + * Validate job forms. + * + * This method will be called when user will try to create new job in the + * system. It must return FINE or ACCEPTABLE in order to proceed and save + * the job in metadata repository. + * + * Default implementation will delegate the job to validate(MForm). + * + * @param job Job to be validated + * @return Validation status + */ + public Status validate(MJobForms job) { + return validate(job.getForms()); + } + +}