View Javadoc

1   package org.apache.helix.webapp.resources;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.Map;
24  
25  import org.apache.helix.HelixDataAccessor;
26  import org.apache.helix.HelixException;
27  import org.apache.helix.PropertyKey;
28  import org.apache.helix.ZNRecord;
29  import org.apache.helix.PropertyKey.Builder;
30  import org.apache.helix.manager.zk.ZkClient;
31  import org.apache.helix.model.IdealState;
32  import org.apache.helix.tools.ClusterSetup;
33  import org.apache.helix.webapp.RestAdminApplication;
34  import org.apache.log4j.Logger;
35  import org.codehaus.jackson.JsonGenerationException;
36  import org.codehaus.jackson.map.JsonMappingException;
37  import org.restlet.Context;
38  import org.restlet.data.MediaType;
39  import org.restlet.data.Request;
40  import org.restlet.data.Response;
41  import org.restlet.data.Status;
42  import org.restlet.resource.Representation;
43  import org.restlet.resource.Resource;
44  import org.restlet.resource.StringRepresentation;
45  import org.restlet.resource.Variant;
46  
47  
48  public class IdealStateResource extends Resource
49  {
50    private final static Logger LOG = Logger.getLogger(IdealStateResource.class);
51  
52    public IdealStateResource(Context context, Request request, Response response)
53    {
54      super(context, request, response);
55      getVariants().add(new Variant(MediaType.TEXT_PLAIN));
56      getVariants().add(new Variant(MediaType.APPLICATION_JSON));
57    }
58  
59    @Override
60    public boolean allowGet()
61    {
62      return true;
63    }
64  
65    @Override
66    public boolean allowPost()
67    {
68      return true;
69    }
70  
71    @Override
72    public boolean allowPut()
73    {
74      return false;
75    }
76  
77    @Override
78    public boolean allowDelete()
79    {
80      return false;
81    }
82  
83    @Override
84    public Representation represent(Variant variant)
85    {
86      StringRepresentation presentation = null;
87      try
88      {
89        String clusterName = (String) getRequest().getAttributes().get("clusterName");
90        String resourceName = (String) getRequest().getAttributes().get("resourceName");
91        presentation = getIdealStateRepresentation(clusterName, resourceName);
92      }
93  
94      catch (Exception e)
95      {
96        String error = ClusterRepresentationUtil.getErrorAsJsonStringFromException(e);
97        presentation = new StringRepresentation(error, MediaType.APPLICATION_JSON);
98  
99        LOG.error("", e);
100     }
101     return presentation;
102   }
103 
104   StringRepresentation getIdealStateRepresentation(String clusterName, String resourceName) throws JsonGenerationException,
105       JsonMappingException,
106       IOException
107   {
108     Builder keyBuilder = new PropertyKey.Builder(clusterName);
109     ZkClient zkClient =
110         (ZkClient) getContext().getAttributes().get(RestAdminApplication.ZKCLIENT);
111 
112     String message =
113         ClusterRepresentationUtil.getClusterPropertyAsString(zkClient,
114                                                              clusterName,
115                                                              keyBuilder.idealStates(resourceName),
116                                                              MediaType.APPLICATION_JSON);
117 
118     StringRepresentation representation =
119         new StringRepresentation(message, MediaType.APPLICATION_JSON);
120 
121     return representation;
122   }
123 
124   @Override
125   public void acceptRepresentation(Representation entity)
126   {
127     try
128     {
129       String clusterName = (String) getRequest().getAttributes().get("clusterName");
130       String resourceName = (String) getRequest().getAttributes().get("resourceName");
131       ZkClient zkClient =
132           (ZkClient) getContext().getAttributes().get(RestAdminApplication.ZKCLIENT);
133       ClusterSetup setupTool = new ClusterSetup(zkClient);
134 
135       JsonParameters jsonParameters = new JsonParameters(entity);
136       String command = jsonParameters.getCommand();
137 
138       if (command.equalsIgnoreCase(ClusterSetup.addIdealState))
139       {
140         ZNRecord newIdealState = jsonParameters.getExtraParameter(JsonParameters.NEW_IDEAL_STATE);
141         HelixDataAccessor accessor =
142             ClusterRepresentationUtil.getClusterDataAccessor(zkClient, clusterName);
143 
144         accessor.setProperty(accessor.keyBuilder().idealStates(resourceName),
145                              new IdealState(newIdealState));
146 
147       }
148       else if (command.equalsIgnoreCase(ClusterSetup.rebalance))
149       {
150         int replicas = 
151             Integer.parseInt(jsonParameters.getParameter(JsonParameters.REPLICAS));
152         String keyPrefix = jsonParameters.getParameter(JsonParameters.RESOURCE_KEY_PREFIX);
153         String groupTag = jsonParameters.getParameter(ClusterSetup.instanceGroupTag);
154         
155           setupTool.rebalanceCluster(clusterName,
156                                             resourceName,
157                                             replicas,
158                                             keyPrefix,
159                                             groupTag);
160        
161       }
162       else if (command.equalsIgnoreCase(ClusterSetup.expandResource))
163       {
164         setupTool.expandResource(clusterName, resourceName);
165       }
166       else if (command.equalsIgnoreCase(ClusterSetup.addResourceProperty))
167       {
168         Map<String, String> parameterMap = jsonParameters.cloneParameterMap();
169         parameterMap.remove(JsonParameters.MANAGEMENT_COMMAND);
170         for (String key : parameterMap.keySet())
171         {
172           setupTool.addResourceProperty(clusterName,
173                                         resourceName,
174                                         key,
175                                         parameterMap.get(key));
176         }
177       }
178       else
179       {
180         throw new HelixException("Unsupported command: " + command
181             + ". Should be one of [" + ClusterSetup.addIdealState + ", "
182             + ClusterSetup.rebalance + ", " + ClusterSetup.expandResource + ", "
183             + ClusterSetup.addResourceProperty + "]");
184       }
185 
186       getResponse().setEntity(getIdealStateRepresentation(clusterName, resourceName));
187       getResponse().setStatus(Status.SUCCESS_OK);
188     }
189     catch (Exception e)
190     {
191       getResponse().setEntity(ClusterRepresentationUtil.getErrorAsJsonStringFromException(e),
192                               MediaType.APPLICATION_JSON);
193       getResponse().setStatus(Status.SUCCESS_OK);
194       LOG.error("Error in posting " + entity, e);
195     }
196   }
197 }