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 019package org.apache.hadoop.registry.client.impl.zk; 020 021import com.google.common.base.Preconditions; 022import org.apache.hadoop.classification.InterfaceAudience; 023import org.apache.hadoop.classification.InterfaceStability; 024import org.apache.hadoop.registry.client.api.BindFlags; 025import org.apache.hadoop.registry.client.api.RegistryOperations; 026 027import org.apache.hadoop.registry.client.binding.RegistryTypeUtils; 028import org.apache.hadoop.registry.client.binding.RegistryUtils; 029import org.apache.hadoop.registry.client.binding.RegistryPathUtils; 030import org.apache.hadoop.registry.client.exceptions.InvalidPathnameException; 031import org.apache.hadoop.registry.client.exceptions.NoRecordException; 032import org.apache.hadoop.registry.client.types.RegistryPathStatus; 033import org.apache.hadoop.registry.client.types.ServiceRecord; 034import org.apache.zookeeper.CreateMode; 035import org.apache.zookeeper.data.ACL; 036import org.apache.zookeeper.data.Stat; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import java.io.IOException; 041import 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 056public 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}