【问题标题】:Akamai CCU V3 Fast Purge implementation with JAVA project or AEM使用 JAVA 项目或 AEM 实施 Akamai CCU V3 快速清除
【发布时间】:2018-02-26 05:53:36
【问题描述】:

有没有人尝试通过快速清除将 Java 代码从 CCU V2 集成到 CCU V3。我阅读了文档,但无法理解在基于 java 的项目中需要做什么。在 Akamai 控制台中配置客户端后,我们如何编写代码以访问和清除。 非常感谢任何帮助。

谢谢, 图沙尔

【问题讨论】:

    标签: java aem akamai


    【解决方案1】:

    一般的方法是编写一些代码向快速清除端点发出 HTTP 请求。

    这是一个例子:

    import com.akamai.edgegrid.auth.*;
    //other imports
    
    public void callAkamaiFastPurgeForUrls(Set<String> urlsToPurge) throws URISyntaxException, IOException, RequestSigningException {
        if(!urlsToPurge.isEmpty()) {
            int status;
            String json = getPurgeJson(urlsToPurge);
            HttpRequest signedRequest = getHttpRequest(json, compProperty);
            HttpResponse response = signedRequest.execute();
    
            status = response.getStatusCode();
    
            if (status == 201) {
                //handle success responses as you see fit
            } else {
                //handle non-success responses as you see fit
            }
        }
    }
    
    private static String getPurgeJson(Set<String> pathsToPurge) {
        //your code to turn the list of urls into JSON in this format:
        //{"objects":["https://www.yourdomain.com/page1.html","https://www.yourdomain.com/page2.html"]}
    
        return //JSON string such as the example above
    }
    
    
    private HttpRequest getHttpRequest(String json, Dictionary<String, Object> dispatcherAndAkamaiServletProperties) throws URISyntaxException, IOException, RequestSigningException {
        String hostName = yourCodeToFetchConfigValues("hostname");
        String accessToken = yourCodeToFetchConfigValues("accesstoken");
        String clientToken = yourCodeToFetchConfigValues("clienttoken");
        String clientSecret = yourCodeToFetchConfigValues("clientsecret");
        String apiUrl = yourCodeToFetchConfigValues("apiurl");
        String proxyServer = yourCodeToFetchConfigValues("proxyhostakamai");
        int proxyPort = yourCodeToFetchConfigValues("proxyport");
    
        HttpTransport httpTransport = new NetHttpTransport.Builder()
                .setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, proxyPort))).build();
    
        HttpRequestFactory requestFactory = httpTransport.createRequestFactory();
    
        URI uri = new URI(HTTPS, hostName, apiUrl, null, null);
        HttpContent body = new ByteArrayContent("application/json", json.getBytes());
        HttpRequest request = requestFactory.buildPostRequest(new GenericUrl(uri), body);
        HttpHeaders headers = request.getHeaders();
        headers.set("Host", hostName);
        ClientCredential credential = new DefaultCredential(clientToken, accessToken, clientSecret);
        RequestSigner signer = new EdgeGridV1Signer(Collections.emptyList(), 1024 * 2);
    
        return signer.sign(request, credential);
    }
    

    此外,您可能需要更新您的信任库以包含您正在调用的 Akamai 端点的证书,以便进行 SSL 通信。

    【讨论】:

      【解决方案2】:

      @Shawn 的回答大多是正确的。尽管您希望拥有更多的东西,例如自定义复制代理、自定义内容构建器和传输处理程序(如果您将其与 AEM 集成)。此外,也可能很少有依赖性问题。 如果您在所有这些方面需要帮助,可以参考以下文章: https://www.linkedin.com/pulse/akamai-cache-purge-aem-through-java-code-shubham-saxena/

      对于传输处理程序,您可以使用以下 sn-p:

          package com.myproject.bundle.core.services.impl;
      
      import java.io.IOException;
      import java.net.URI;
      import java.nio.charset.Charset;
      
      import org.apache.commons.io.IOUtils;
      import org.apache.commons.lang3.StringUtils;
      import org.apache.http.HttpStatus;
      import org.apache.http.entity.ContentType;
      import org.apache.jackrabbit.util.Base64;
      import org.apache.sling.api.resource.ValueMap;
      import org.apache.sling.commons.json.JSONArray;
      import org.apache.sling.commons.json.JSONException;
      import org.apache.sling.commons.json.JSONObject;
      import org.apache.sling.commons.osgi.PropertiesUtil;
      import org.osgi.service.component.annotations.Component;
      import org.osgi.service.component.annotations.Reference;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import com.akamai.edgegrid.signer.ClientCredential;
      import com.akamai.edgegrid.signer.exceptions.RequestSigningException;
      import com.akamai.edgegrid.signer.googlehttpclient.GoogleHttpClientEdgeGridRequestSigner;
      import com.day.cq.replication.AgentConfig;
      import com.day.cq.replication.ReplicationActionType;
      import com.day.cq.replication.ReplicationException;
      import com.day.cq.replication.ReplicationResult;
      import com.day.cq.replication.ReplicationTransaction;
      import com.day.cq.replication.TransportContext;
      import com.day.cq.replication.TransportHandler;
      import com.myproject.bundle.core.configuration.BaseConfigurationService;
      import com.myproject.bundle.core.constants.MyConstants;
      import com.myproject.bundle.core.search.services.MyProjectConfigurationService;
      import com.google.api.client.http.ByteArrayContent;
      import com.google.api.client.http.GenericUrl;
      import com.google.api.client.http.HttpHeaders;
      import com.google.api.client.http.HttpRequest;
      import com.google.api.client.http.HttpRequestFactory;
      import com.google.api.client.http.HttpResponse;
      import com.google.api.client.http.HttpTransport;
      import com.google.api.client.http.apache.ApacheHttpTransport;
      
      /**
       * Transport handler to send test and purge requests to Akamai and handle
       * responses. The handler sets up basic authentication with the user/pass from
       * the replication agent's transport config and sends a GET request as a test
       * and POST as purge request. A valid test response is 200 while a valid purge
       * response is 201.
       * 
       * The transport handler is triggered by setting your replication agent's
       * transport URL's protocol to "akamai://".
       *
       * The transport handler builds the POST request body in accordance with
       * Akamai's Fast Purge REST API {@link https://developer.akamai.com/api/core_features/fast_purge/v3.html}
       * using the replication agent properties. 
       */
      @Component(service = TransportHandler.class, immediate = true)
      public class AkamaiTransportHandler implements TransportHandler {
      
          /**The Solr Server Configuration Service.*/
          @Reference
          MyProjectConfigurationService myProjectConfigurationService;
      
          @Reference
          BaseConfigurationService baseConfigurationService;
      
          /**Logger Instantiation for Akamai Transport Handler*/
          private static final Logger LOGGER = LoggerFactory.getLogger(AkamaiTransportHandler.class);
      
          /** Protocol for replication agent transport URI that triggers this transport handler. */
          private static final String AKAMAI_PROTOCOL = "akamai://";
      
          /**Config Pid for Akamai Flush*/
          private static final String AKAMAI_FLUSH_CONFIG_PID = "com.myproject.bundle.core.configuration.AkamaiFlushConfiguration";
      
          /** Replication agent type property name. Valid values are "arl" and "cpcode". */
          private static final String PROPERTY_AKAMAI_TYPE = "type";
      
          /** Replication agent multifield CP Code property name.*/
          private static final String PROPERTY_AKAMAI_CP_CODES = "4321xxx";
      
          /** Replication agent domain property name. Valid values are "staging" and "production". */
          private static final String PROPERTY_AKAMAI_DOMAIN = "domain";
      
          /** Replication agent action property name. Valid values are "remove" and "invalidate". */
          private static final String PROPERTY_AKAMAI_ACTION = "action";
      
          /** Replication agent default type value */
          private static final String PROPERTY_AKAMAI_TYPE_DEFAULT = "url";
      
          /** Replication agent default domain value */
          private static final String PROPERTY_AKAMAI_DOMAIN_DEFAULT = "production";
      
          /** Replication agent default action value */
          private static final String PROPERTY_AKAMAI_ACTION_DEFAULT = "invalidate";
      
          /**Transport URI*/
          private static final String TRANSPORT_URI = "transportUri";
      
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean canHandle(AgentConfig config) {
              final String transportURI = config.getTransportURI();
      
              return (transportURI != null) && (transportURI.toLowerCase().startsWith(AKAMAI_PROTOCOL));
          }
      
          /**
           * {@inheritDoc}
           */
          @Override
          public ReplicationResult deliver(TransportContext ctx, ReplicationTransaction tx)
                  throws ReplicationException {
      
              final ReplicationActionType replicationType = tx.getAction().getType();
      
              if (replicationType == ReplicationActionType.TEST) {
                  return ReplicationResult.OK;
              } else if (replicationType == ReplicationActionType.ACTIVATE ||
                      replicationType == ReplicationActionType.DEACTIVATE ||
                      replicationType == ReplicationActionType.DELETE) {
                  LOGGER.info("Replication  Type in Akamai Handler: {}", replicationType);
                  String resourcePath = tx.getAction().getPath();
                  if (StringUtils.startsWith(resourcePath, myProjectConfigurationService.getContentpath()) 
                      || StringUtils.startsWith(resourcePath, myProjectConfigurationService.getAssetpath())) {
      // checking for my project specific root page and root dam path.
                      LOGGER.info("Calling activate in Akamai for path: {}", resourcePath);
                      try {
                          return doActivate(ctx, tx);
                      } catch (RequestSigningException e) {
                          LOGGER.error("Signing ceremony unsuccessful....");
                          throw new ReplicationException("Signing ceremony unsuccessful: {}", e);
                      } catch (IOException e) {
                          LOGGER.error("IO Exception in deliver \n");
                          throw new ReplicationException("IO Exception in deliver: {}", e);
                      }
                  }
                  return ReplicationResult.OK;
              } else {
                  throw new ReplicationException("Replication action type " + replicationType + " not supported.");
              }
          }
      
          private String getTransportURI(TransportContext ctx) throws IOException {
              LOGGER.info("Entering getTransportURI method.");
              final ValueMap properties = ctx.getConfig().getProperties();
              final String AKAMAI_HOST = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiHost");
              final String domain = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_DOMAIN), PROPERTY_AKAMAI_DOMAIN_DEFAULT);
              final String action = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_ACTION), PROPERTY_AKAMAI_ACTION_DEFAULT);
              final String type = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_TYPE), PROPERTY_AKAMAI_TYPE_DEFAULT);
              String defaultTransportUri = MyConstants.HTTPS + AKAMAI_HOST + "/ccu/v3/"
                                          + action + MyConstants.BACK_SLASH + type + MyConstants.BACK_SLASH + domain;
              String transporturi = PropertiesUtil.toString(properties.get(TRANSPORT_URI), defaultTransportUri);
      
              if(StringUtils.isEmpty(transporturi)) {
                  return defaultTransportUri;
              }
              if (transporturi.startsWith(AKAMAI_PROTOCOL)) {
                  transporturi = transporturi.replace(AKAMAI_PROTOCOL, MyConstants.HTTPS);
              }
              transporturi =  transporturi + "/ccu/v3/"
                      + action + MyConstants.BACK_SLASH + type + MyConstants.BACK_SLASH + domain;
              LOGGER.info("Exiting getTransportURI method of Akamai Transport Handler : {}", transporturi);
              return transporturi;
          }
      
          /**
           * Send purge request to Akamai via a POST request
           *
           * Akamai will respond with a 201 HTTP status code if the purge request was
           * successfully submitted.
           *
           * @param ctx Transport Context
           * @param tx Replication Transaction
           * @return ReplicationResult OK if 201 response from Akamai
           * @throws ReplicationException
           * @throws RequestSigningException 
           * @throws IOException 
           * @throws JSONException 
           */
          private ReplicationResult doActivate(TransportContext ctx, ReplicationTransaction tx)
                  throws ReplicationException, RequestSigningException, IOException {
              LOGGER.info("Inside doActivate of Akamai");
              final String AKAMAI_ACCESS_TOKEN = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiAccessToken");
              final String AKAMAI_CLIENT_TOKEN = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiClientToken");
              final String AKAMAI_CLIENT_SECRET = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiClientSecret");
              final String AKAMAI_HOST = baseConfigurationService.getPropValueFromConfiguration(AKAMAI_FLUSH_CONFIG_PID, "akamaiHost");
      
              ClientCredential clientCredential = ClientCredential.builder().accessToken(AKAMAI_ACCESS_TOKEN).
                      clientToken(AKAMAI_CLIENT_TOKEN).clientSecret(AKAMAI_CLIENT_SECRET).host(AKAMAI_HOST).build();
      
      
              HttpTransport httpTransport = new ApacheHttpTransport();
              HttpRequestFactory httpRequestFactory = httpTransport.createRequestFactory();
      
              JSONObject jsonObject = createPostBody(ctx, tx);
      
      
              URI uri = URI.create(getTransportURI(ctx));
      
              HttpRequest request = httpRequestFactory.buildPostRequest(new GenericUrl(uri), ByteArrayContent.fromString("application/json", jsonObject.toString()));
              final HttpResponse response = sendRequest(request, ctx, clientCredential);
      
      
              if (response != null) {
                  final int statusCode = response.getStatusCode();
                  LOGGER.info("Response code recieved: {}", statusCode);
                  if (statusCode == HttpStatus.SC_CREATED) {
                      return ReplicationResult.OK;
                  }
              }
              return new ReplicationResult(false, 0, "Replication failed");
          }
      
          /**
           * Build preemptive basic authentication headers and send request.
           *
           * @param request The request to send to Akamai
           * @param ctx The TransportContext containing the username and password
           * @return JSONObject The HTTP response from Akamai
           * @throws ReplicationException if a request could not be sent
           * @throws RequestSigningException 
           */
          private HttpResponse sendRequest(final HttpRequest request, final TransportContext ctx,
                  ClientCredential clientCredential)
                  throws ReplicationException, RequestSigningException {
      
              LOGGER.info("Inside Send Request method of Akamai");
              final String auth = ctx.getConfig().getTransportUser() + ":" + ctx.getConfig().getTransportPassword();
              final String encodedAuth = Base64.encode(auth);
      
               HttpHeaders httpHeaders = new HttpHeaders();
               httpHeaders.setAuthorization("Basic " + encodedAuth);
               httpHeaders.setContentType(ContentType.APPLICATION_JSON.getMimeType());
      
               request.setHeaders(httpHeaders);
      
               GoogleHttpClientEdgeGridRequestSigner requestSigner = new GoogleHttpClientEdgeGridRequestSigner(clientCredential);
               requestSigner.sign(request);
      
               HttpResponse response;
      
               try {
                   response = request.execute();
               } catch (IOException e) {
                   LOGGER.error("IO Exception in sendRequest");
                   throw new ReplicationException("Could not send replication request.", e);
               }
               LOGGER.info("Sucessfully executed Send Request for Akamai");
               return response;
          }
      
          /**
           * Build the Akamai purge request body based on the replication agent
           * settings and append it to the POST request.
           *
           * @param request The HTTP POST request to append the request body
           * @param ctx TransportContext
           * @param tx ReplicationTransaction
           * @throws ReplicationException if errors building the request body 
           */
          private JSONObject createPostBody(final TransportContext ctx,
                  final ReplicationTransaction tx) throws ReplicationException {
              final ValueMap properties = ctx.getConfig().getProperties();
              final String type = PropertiesUtil.toString(properties.get(PROPERTY_AKAMAI_TYPE), PROPERTY_AKAMAI_TYPE_DEFAULT);
              JSONObject json = new JSONObject();
              JSONArray purgeObjects = null;
      
              if (type.equals(PROPERTY_AKAMAI_TYPE_DEFAULT)) {
                  try {
                      String content = IOUtils.toString(tx.getContent().getInputStream(), Charset.defaultCharset());
      
                      if (StringUtils.isNotBlank(content)) {
                          LOGGER.info("Content of Akamai is:\n {}", content);
                          purgeObjects = new JSONArray(content);
                      }
                  } catch (JSONException | IOException e) {
                      throw new ReplicationException("Could not retrieve content from content builder", e);
                  }
              }
              if (null != purgeObjects && purgeObjects.length() > 0) {
                  try {
                      json.put("objects", purgeObjects);
                  } catch (JSONException e) {
                      throw new ReplicationException("Could not build purge request content", e);
                  }
              } else {
                  throw new ReplicationException("No CP codes or pages to purge");
              }
              return json;
          }
      }
      

      您还需要以下依赖项:

          <dependency>
              <groupId>com.akamai.edgegrid</groupId>
              <artifactId>edgegrid-signer-google-http-client</artifactId>
              <version>4.0.0</version>
          </dependency>
          <dependency>
              <groupId>com.akamai.edgegrid</groupId>
              <artifactId>edgegrid-signer-core</artifactId>
              <version>4.0.0</version>
          </dependency>
          <dependency>
              <groupId>com.google.http-client</groupId>
              <artifactId>google-http-client</artifactId>
              <version>1.22.0</version>
          </dependency>
      

      对于我的情况,捆绑包没有解析,我必须添加以下依赖项来解决它。不过,您的情况可能会有所不同:

          <dependency>
              <groupId>io.opencensus</groupId>
              <artifactId>opencensus-api</artifactId>
              <version>0.24.0</version>
          </dependency>
          <dependency>
              <groupId>io.opencensus</groupId>
              <artifactId>opencensus-contrib-http-util</artifactId>
              <version>0.24.0</version>
          </dependency>
          <dependency>
              <groupId>io.grpc</groupId>
              <artifactId>grpc-context</artifactId>
              <version>1.24.0</version>
          </dependency>
       <Import-Package>
              javax.annotation;version=0.0.0,
       </Import-Package>
      

      对于“IOUtils.toString(tx.getContent().getInputStream(), Charset.defaultCharset());”这一行,它在内部调用您的自定义内容构建器(您可以参考我之前提供的文章链接)。但是,您可以直接在传输处理程序本身中创建内容对象,因为传输处理程序无论如何都会创建它自己的请求。但是,如果您需要会话,则需要实现 ContentBuilder,因为 TransportHandler 实现不提供这种杠杆作用。

      谢谢, 舒巴姆

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-27
        • 2021-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-16
        相关资源
        最近更新 更多