1   /*
2    * (C) Copyright 1989-2011 Trend Micro, Inc.
3    * All Rights Reserved.
4    *
5    * This program is an unpublished copyrighted work which is proprietary
6    * to Trend Micro, Inc. and contains confidential information that is not
7    * to be reproduced or disclosed to any other person or entity without
8    * prior written consent from Trend Micro, Inc. in each and every instance.
9    *
10   * WARNING:  Unauthorized reproduction of this program as well as
11   * unauthorized preparation of derivative works based upon the
12   * program or distribution of copies by sale, rental, lease or
13   * lending are violations of federal copyright laws and state trade
14   * secret laws, punishable by civil and criminal penalties.
15   */
16  
17  package com.trendmicro.grid.acl.l0;
18  
19  import com.trendmicro.grid.acl.client.AbstractClient;
20  import com.trendmicro.grid.acl.l0.datatypes.NameList;
21  import com.trendmicro.grid.acl.l0.datatypes.UsageStatistics;
22  import com.trendmicro.grid.acl.l0.datatypes.UsageStatisticsCollection;
23  import org.springframework.beans.factory.annotation.Autowired;
24  import org.springframework.stereotype.Service;
25  
26  import javax.annotation.PostConstruct;
27  import javax.annotation.Resource;
28  import javax.ws.rs.*;
29  import java.util.Collection;
30  import java.util.LinkedHashSet;
31  import java.util.Set;
32  
33  /**
34   * Implements a REST service that provides the values offered by the server statistics service.
35   *
36   * @author Juergen_Kellerer, 2011-04-12
37   * @version 1.0
38   */
39  @Service
40  @Path("/internal/server-statistics")
41  @Produces({"application/xml", "application/json"})
42  public class ServerStatisticsRestService implements Level0RestService {
43  
44  	@Resource
45  	InternalCacheControlService cacheControlService;
46  	@Resource
47  	ServerStatisticsService localStatisticsService;
48  	@Autowired(required = false)
49  	Collection<AbstractClient> soapClients;
50  
51  	AbstractClient<ServerStatisticsService> statisticsServiceClient;
52  
53  	@PostConstruct
54  	@SuppressWarnings("unchecked")
55  	void selectServiceClient() {
56  		if (soapClients != null) {
57  			Class<ServerStatisticsService> eif = ServerStatisticsService.class;
58  			for (AbstractClient soapClient : soapClients)
59  				if (eif.equals(soapClient.getEndpointInterface()))
60  					statisticsServiceClient = (AbstractClient<ServerStatisticsService>) soapClient;
61  
62  			if (statisticsServiceClient == null) {
63  				throw new IllegalStateException("No soap client was found that satisfies " +
64  						"the endpoint interface " + eif);
65  			}
66  		}
67  	}
68  
69  	ServerStatisticsService selectStatisticsService(String nodeName) {
70  		RestUtil.assertIsNotCrossSiteScriptingVulnerable(nodeName);
71  
72  		if (nodeName == null || nodeName.isEmpty() || statisticsServiceClient == null ||
73  				"localhost".equalsIgnoreCase(nodeName) || nodeName.startsWith("127.0"))
74  			return localStatisticsService;
75  		else {
76  			if (extractNetworkAddresses(
77  					cacheControlService.getLocalClusterNodeAddressListInternal()).contains(nodeName))
78  				return localStatisticsService;
79  
80  			Set<String> validNodeNames = extractNetworkAddresses(
81  					cacheControlService.getCacheClusterNodeAddressListInternal());
82  			if (!validNodeNames.contains(nodeName)) {
83  				throw new IllegalArgumentException("Specified a node name of '" + nodeName +
84  						"' that is not contained within " + validNodeNames);
85  			}
86  
87  			return statisticsServiceClient.getRemotePort(nodeName);
88  		}
89  	}
90  
91  	Set<String> extractNetworkAddresses(Collection<String> sourceAddresses) {
92  		Set<String> addresses = new LinkedHashSet<String>(sourceAddresses.size());
93  		for (String sourceAddress : sourceAddresses) {
94  			int idx = sourceAddress.indexOf('@');
95  			if (idx == -1)
96  				continue;
97  			addresses.add(sourceAddress.substring(idx + 1));
98  		}
99  		return addresses;
100 	}
101 
102 	/**
103 	 * Returns the node names (=node-addresses) of all ACL nodes within a cache cluster.
104 	 *
105 	 * @return the node names (=node-addresses) of all ACL nodes within a cache cluster.
106 	 */
107 	@GET
108 	@Path("/nodeNames")
109 	public NameList getNodeNames() {
110 		Set<String> addresses = extractNetworkAddresses(cacheControlService.getCacheClusterNodeAddressListInternal());
111 		return new NameList(addresses);
112 	}
113 
114 	/**
115 	 * Delegates to {@link ServerStatisticsService#getOverallUsageStatistics()}.
116 	 * <p/>
117 	 * The rest service optionally accepts to specify a node name allowing to retrieve the value from
118 	 * another node than the one it connected to.
119 	 * (This allows cross site scripting on this particular service,
120 	 * which is needed to display multiple node's data on a single page)
121 	 *
122 	 * @param nodeName the optional name of the node (defaults to 'localhost').
123 	 * @return the delegate's return value.
124 	 */
125 	@GET
126 	@Path("/overallUsageStatistics/{nodeName}")
127 	public UsageStatistics getOverallUsageStatistics(
128 			@DefaultValue("localhost") @PathParam("nodeName") String nodeName) {
129 		return selectStatisticsService(nodeName).getOverallUsageStatistics();
130 	}
131 
132 	/**
133 	 * Delegates to {@link ServerStatisticsService#getCurrentUsageStatistics()}.
134 	 * <p/>
135 	 * The rest service optionally accepts to specify a node name allowing to retrieve the value from
136 	 * another node than the one it connected to.
137 	 * (This allows cross site scripting on this particular service,
138 	 * which is needed to display multiple node's data on a single page)
139 	 *
140 	 * @param nodeName the optional name of the node (defaults to 'localhost').
141 	 * @return the delegate's return value.
142 	 */
143 	@GET
144 	@Path("/currentUsageStatistics/{nodeName}")
145 	public UsageStatistics getCurrentUsageStatistics(
146 			@DefaultValue("localhost") @PathParam("nodeName") String nodeName) {
147 		return selectStatisticsService(nodeName).getCurrentUsageStatistics();
148 	}
149 
150 	/**
151 	 * Delegates to {@link ServerStatisticsService#getCollectedUsageStatistics()}.
152 	 * <p/>
153 	 * The rest service optionally accepts to specify a node name allowing to retrieve the value from
154 	 * another node than the one it connected to.
155 	 * (This allows cross site scripting on this particular service,
156 	 * which is needed to display multiple node's data on a single page)
157 	 *
158 	 * @param nodeName the optional name of the node (defaults to 'localhost').
159 	 * @return the delegate's return value.
160 	 */
161 	@GET
162 	@Path("/collectedUsageStatistics/{nodeName}")
163 	public UsageStatisticsCollection getCollectedUsageStatistics(
164 			@DefaultValue("localhost") @PathParam("nodeName") String nodeName) {
165 		return selectStatisticsService(nodeName).getCollectedUsageStatistics();
166 	}
167 }