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 }