001/*
002 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     akervern, jcarsique
018 */
019
020package org.nuxeo.launcher.connect;
021
022import java.io.IOException;
023import java.util.List;
024import java.util.Map;
025import java.util.Optional;
026import java.util.function.Predicate;
027import java.util.regex.Pattern;
028import java.util.stream.Stream;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.apache.commons.validator.routines.EmailValidator;
033import org.nuxeo.connect.NuxeoConnectClient;
034import org.nuxeo.connect.connector.NuxeoClientInstanceType;
035import org.nuxeo.connect.data.ConnectProject;
036import org.nuxeo.connect.identity.LogicalInstanceIdentifier;
037import org.nuxeo.connect.registration.ConnectRegistrationService;
038import org.nuxeo.connect.registration.RegistrationException;
039import org.nuxeo.connect.registration.RegistrationHelper;
040import org.nuxeo.launcher.config.ConfigurationException;
041
042/**
043 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a>
044 * @since 8.3
045 */
046public class ConnectRegistrationBroker {
047
048    /**
049     * @since 9.2
050     */
051    public enum TrialField {
052        FIRST_NAME( //
053                "firstName", //
054                "First name", //
055                input -> Pattern.matches("^(\\p{Alnum}+)([\\s-]\\p{Alnum}+)*", input), //
056                "Invalid first name: only letters (without accents), space, and hyphen '-' are accepted." //
057        ), LAST_NAME( //
058                "lastName", //
059                "Last name", //
060                input -> Pattern.matches("^(\\p{Alnum}+)([\\s-]\\p{Alnum}+)*", input), //
061                "Invalid last name: only letters (without accents), space, and hyphen '-' are accepted." //
062        ), EMAIL( //
063                "email", //
064                "Email", //
065                input -> EmailValidator.getInstance().isValid(input), //
066                "Invalid email address." //
067        ), COMPANY( //
068                "company", //
069                "Company", //
070                input -> Pattern.matches("^(\\p{Alnum}+)([\\s-]\\p{Alnum}+)*", input),
071                "Invalid company name: only alphanumeric (without accents), space, and hyphen '-' are accepted." //
072        ), PROJECT( //
073                "connectreg:projectName", //
074                "Project name", //
075                input -> Pattern.matches("^(?:[-\\w]+|)$", input), //
076                "Project name can only contain alphanumeric characters and dashes." //
077        ), TERMS_AND_CONDITIONS( //
078                "termsAndConditions", //
079                "Terms and conditions", //
080                input -> true, // always valid
081                "Unused message." //
082        );
083
084        private String id;
085
086        private String name;
087
088        private Predicate<String> predicate;
089
090        private String errorMessage;
091
092        TrialField(String id, String name, Predicate<String> predicate, String errorMessage) {
093            this.id = id;
094            this.name = name;
095            this.predicate = predicate;
096            this.errorMessage = errorMessage;
097        }
098
099        /**
100         * @since 9.2
101         */
102        public String getId() {
103            return id;
104        }
105
106        /**
107         * @since 9.2
108         */
109        public String getPromptMessage() {
110            return name + ": ";
111        }
112
113        /**
114         * @since 9.2
115         */
116        public Predicate<String> getPredicate() {
117            return predicate;
118        }
119
120        /**
121         * @since 9.2
122         */
123        public String getErrorMessage() {
124            return errorMessage;
125        }
126    }
127
128    private static final Log log = LogFactory.getLog(ConnectRegistrationBroker.class);
129
130    protected static ConnectRegistrationService registration() {
131        return NuxeoConnectClient.getConnectRegistrationService();
132    }
133
134    public void registerTrial(Map<String, String> parameters)
135            throws IOException, RegistrationException, ConfigurationException {
136        try {
137            registration().remoteTrialInstanceRegistration(parameters);
138        } catch (LogicalInstanceIdentifier.InvalidCLID e) {
139            log.debug(e, e);
140            throw new ConfigurationException("Instance registration failed.", e);
141        }
142    }
143
144    public void registerLocal(String strCLID, String description) throws IOException, ConfigurationException {
145        try {
146            registration().localRegisterInstance(strCLID, description);
147        } catch (LogicalInstanceIdentifier.InvalidCLID e) {
148            log.debug(e, e);
149            throw new ConfigurationException("Instance registration failed.", e);
150        }
151    }
152
153    public void registerRemote(String username, char[] password, String projectId, NuxeoClientInstanceType type,
154            String description) throws IOException, ConfigurationException {
155        String strCLID = RegistrationHelper.remoteRegisterInstance(username, new String(password), projectId, type,
156                description);
157        registerLocal(strCLID, description);
158    }
159
160    /**
161     * Find a project by its symbolic name, ignoring case
162     *
163     * @param projectName project symbolic name
164     * @param availableProjects projects in which to to look for {@code project}
165     * @return the project or null if not found
166     */
167    public ConnectProject getProjectByName(final String projectName, List<ConnectProject> availableProjects) {
168        Stream<ConnectProject> projectStream = availableProjects.stream();
169        Optional<ConnectProject> pkg = projectStream.filter(
170                availProject -> projectName.equalsIgnoreCase(availProject.getSymbolicName())).findFirst();
171        if (!pkg.isPresent()) {
172            return null;
173        }
174        return pkg.get();
175    }
176
177    public List<ConnectProject> getAvailableProjects(String username, char[] password) throws ConfigurationException {
178        List<ConnectProject> studioProjects = registration().getAvailableProjectsForRegistration(username,
179                new String(password));
180        if (studioProjects.isEmpty()) {
181            throw new ConfigurationException("Wrong login or password.");
182        }
183        return studioProjects;
184    }
185}