001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.registry.client.impl.zk;
020    
021    import com.google.common.base.Preconditions;
022    import org.apache.hadoop.classification.InterfaceAudience;
023    import org.apache.hadoop.classification.InterfaceStability;
024    import org.apache.hadoop.registry.client.api.BindFlags;
025    import org.apache.hadoop.registry.client.api.RegistryOperations;
026    
027    import org.apache.hadoop.registry.client.binding.RegistryTypeUtils;
028    import org.apache.hadoop.registry.client.binding.RegistryUtils;
029    import org.apache.hadoop.registry.client.binding.RegistryPathUtils;
030    import org.apache.hadoop.registry.client.exceptions.InvalidPathnameException;
031    import org.apache.hadoop.registry.client.exceptions.NoRecordException;
032    import org.apache.hadoop.registry.client.types.RegistryPathStatus;
033    import org.apache.hadoop.registry.client.types.ServiceRecord;
034    import org.apache.zookeeper.CreateMode;
035    import org.apache.zookeeper.data.ACL;
036    import org.apache.zookeeper.data.Stat;
037    import org.slf4j.Logger;
038    import org.slf4j.LoggerFactory;
039    
040    import java.io.IOException;
041    import java.util.List;
042    
043    /**
044     * The Registry operations service.
045     * <p>
046     * This service implements the {@link RegistryOperations}
047     * API by mapping the commands to zookeeper operations, and translating
048     * results and exceptions back into those specified by the API.
049     * <p>
050     * Factory methods should hide the detail that this has been implemented via
051     * the {@link CuratorService} by returning it cast to that
052     * {@link RegistryOperations} interface, rather than this implementation class.
053     */
054    @InterfaceAudience.Public
055    @InterfaceStability.Evolving
056    public class RegistryOperationsService extends CuratorService
057      implements RegistryOperations {
058    
059      private static final Logger LOG =
060          LoggerFactory.getLogger(RegistryOperationsService.class);
061    
062      private final RegistryUtils.ServiceRecordMarshal serviceRecordMarshal
063          = new RegistryUtils.ServiceRecordMarshal();
064    
065      public RegistryOperationsService(String name) {
066        this(name, null);
067      }
068    
069      public RegistryOperationsService() {
070        this("RegistryOperationsService");
071      }
072    
073      public RegistryOperationsService(String name,
074          RegistryBindingSource bindingSource) {
075        super(name, bindingSource);
076      }
077    
078      /**
079       * Get the aggregate set of ACLs the client should use
080       * to create directories
081       * @return the ACL list
082       */
083      public List<ACL> getClientAcls() {
084        return getRegistrySecurity().getClientACLs();
085      }
086    
087      /**
088       * Validate a path
089       * @param path path to validate
090       * @throws InvalidPathnameException if a path is considered invalid
091       */
092      protected void validatePath(String path) throws InvalidPathnameException {
093        // currently no checks are performed
094      }
095    
096      @Override
097      public boolean mknode(String path, boolean createParents) throws IOException {
098        validatePath(path);
099        return zkMkPath(path, CreateMode.PERSISTENT, createParents, getClientAcls());
100      }
101    
102      @Override
103      public void bind(String path,
104          ServiceRecord record,
105          int flags) throws IOException {
106        Preconditions.checkArgument(record != null, "null record");
107        validatePath(path);
108        // validate the record before putting it
109        RegistryTypeUtils.validateServiceRecord(path, record);
110        LOG.info("Bound at {} : {}", path, record);
111    
112        CreateMode mode = CreateMode.PERSISTENT;
113        byte[] bytes = serviceRecordMarshal.toBytes(record);
114        zkSet(path, mode, bytes, getClientAcls(),
115            ((flags & BindFlags.OVERWRITE) != 0));
116      }
117    
118      @Override
119      public ServiceRecord resolve(String path) throws IOException {
120        byte[] bytes = zkRead(path);
121    
122        ServiceRecord record = serviceRecordMarshal.fromBytes(path,
123            bytes, ServiceRecord.RECORD_TYPE);
124        RegistryTypeUtils.validateServiceRecord(path, record);
125        return record;
126      }
127    
128      @Override
129      public boolean exists(String path) throws IOException {
130        validatePath(path);
131        return zkPathExists(path);
132      }
133    
134      @Override
135      public RegistryPathStatus stat(String path) throws IOException {
136        validatePath(path);
137        Stat stat = zkStat(path);
138    
139        String name = RegistryPathUtils.lastPathEntry(path);
140        RegistryPathStatus status = new RegistryPathStatus(
141            name,
142            stat.getCtime(),
143            stat.getDataLength(),
144            stat.getNumChildren());
145        if (LOG.isDebugEnabled()) {
146          LOG.debug("Stat {} => {}", path, status);
147        }
148        return status;
149      }
150    
151      @Override
152      public List<String> list(String path) throws IOException {
153        validatePath(path);
154        return zkList(path);
155      }
156    
157      @Override
158      public void delete(String path, boolean recursive) throws IOException {
159        validatePath(path);
160        zkDelete(path, recursive, null);
161      }
162    
163    }