Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ The `google-mail:update-message-labels` data type transformer builds a `ModifyMe

This is useful for modifying Gmail message labels (categorizing, archiving, starring, moving, etc.) without manually calling the labels/list API.

The transformer calls the Gmail API with the credentials configured on the `google-mail` component (for example `camel.component.google-mail.clientId`, `clientSecret` and `refreshToken`, or `serviceAccountKey` and `delegate`). Credentials set only on an endpoint URI do not apply to the transformer.

=== Exchange Variables

[cols="1,1,3"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ public class GoogleCalendarComponent
@Metadata
GoogleCalendarConfiguration configuration;
@Metadata(label = "advanced")
private Calendar client;
@Metadata(label = "advanced")
private GoogleCalendarClientFactory clientFactory;

public GoogleCalendarComponent() {
Expand All @@ -49,23 +47,24 @@ protected GoogleCalendarApiName getApiName(String apiNameStr) {
return getCamelContext().getTypeConverter().convertTo(GoogleCalendarApiName.class, apiNameStr);
}

/**
* Creates a client for the given configuration with the client factory of the component. Each endpoint creates its
* own client from its own options and keeps it for its lifetime.
*/
public Calendar getClient(GoogleCalendarConfiguration config) {
if (client == null) {
if (config.getClientId() != null && !config.getClientId().isBlank()
&& config.getClientSecret() != null && !config.getClientSecret().isBlank()) {
client = getClientFactory().makeClient(config.getClientId(), config.getClientSecret(), config.getScopesAsList(),
config.getApplicationName(), config.getRefreshToken(),
config.getAccessToken(), config.getEmailAddress(), config.getP12FileName(), config.getUser());
} else if (config.getServiceAccountKey() != null && !config.getServiceAccountKey().isBlank()) {
client = getClientFactory().makeClient(getCamelContext(), config.getServiceAccountKey(),
config.getScopesAsList(),
config.getApplicationName(), config.getDelegate());
} else {
throw new IllegalArgumentException(
"(clientId and clientSecret) or serviceAccountKey are required to create Google Calendar client");
}
if (config.getClientId() != null && !config.getClientId().isBlank()
&& config.getClientSecret() != null && !config.getClientSecret().isBlank()) {
return getClientFactory().makeClient(config.getClientId(), config.getClientSecret(), config.getScopesAsList(),
config.getApplicationName(), config.getRefreshToken(),
config.getAccessToken(), config.getEmailAddress(), config.getP12FileName(), config.getUser());
} else if (config.getServiceAccountKey() != null && !config.getServiceAccountKey().isBlank()) {
return getClientFactory().makeClient(getCamelContext(), config.getServiceAccountKey(),
config.getScopesAsList(),
config.getApplicationName(), config.getDelegate());
} else {
throw new IllegalArgumentException(
"(clientId and clientSecret) or serviceAccountKey are required to create Google Calendar client");
}
return client;
}

public GoogleCalendarClientFactory getClientFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.apache.camel.component.google.calendar;

import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.google.api.services.calendar.Calendar;
import org.apache.camel.Category;
Expand Down Expand Up @@ -46,6 +48,8 @@ public class GoogleCalendarEndpoint extends AbstractApiEndpoint<GoogleCalendarAp

@UriParam
private GoogleCalendarConfiguration configuration;
private final Lock clientLock = new ReentrantLock();
private volatile Calendar client;

private Object apiProxy;

Expand Down Expand Up @@ -116,8 +120,24 @@ protected void afterConfigureProperties() {
}
}

/**
* The client of this endpoint, created on first use from the options of this endpoint and kept for the lifetime of
* the endpoint.
*/
public Calendar getClient() {
return ((GoogleCalendarComponent) getComponent()).getClient(configuration);
Calendar answer = client;
if (answer == null) {
clientLock.lock();
try {
if (client == null) {
client = ((GoogleCalendarComponent) getComponent()).getClient(configuration);
}
answer = client;
} finally {
clientLock.unlock();
}
}
return answer;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
@Component("google-calendar-stream")
public class GoogleCalendarStreamComponent extends HealthCheckComponent {

@Metadata(label = "advanced")
private Calendar client;
@Metadata(label = "advanced")
private GoogleCalendarClientFactory clientFactory;
@Metadata
Expand All @@ -47,22 +45,23 @@ public GoogleCalendarStreamComponent(CamelContext context) {
this.configuration = new GoogleCalendarStreamConfiguration();
}

/**
* Creates a client for the given configuration with the client factory of the component. Each endpoint creates its
* own client from its own options and keeps it for its lifetime.
*/
public Calendar getClient(GoogleCalendarStreamConfiguration config) {
if (client == null) {
if (config.getClientId() != null && config.getClientSecret() != null) {
client = getClientFactory().makeClient(config.getClientId(), config.getClientSecret(), config.getScopesAsList(),
config.getApplicationName(), config.getRefreshToken(),
config.getAccessToken(), config.getEmailAddress(), config.getP12FileName(), config.getUser());
} else if (config.getServiceAccountKey() != null) {
client = getClientFactory().makeClient(getCamelContext(), config.getServiceAccountKey(),
config.getScopesAsList(),
config.getApplicationName(), config.getDelegate());
} else {
throw new IllegalArgumentException(
"(clientId and clientSecret) or serviceAccountKey are required to create Gmail client");
}
if (config.getClientId() != null && config.getClientSecret() != null) {
return getClientFactory().makeClient(config.getClientId(), config.getClientSecret(), config.getScopesAsList(),
config.getApplicationName(), config.getRefreshToken(),
config.getAccessToken(), config.getEmailAddress(), config.getP12FileName(), config.getUser());
} else if (config.getServiceAccountKey() != null) {
return getClientFactory().makeClient(getCamelContext(), config.getServiceAccountKey(),
config.getScopesAsList(),
config.getApplicationName(), config.getDelegate());
} else {
throw new IllegalArgumentException(
"(clientId and clientSecret) or serviceAccountKey are required to create Google Calendar client");
}
return client;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.apache.camel.component.google.calendar.stream;

import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.model.Event;
Expand Down Expand Up @@ -46,6 +48,8 @@ public class GoogleCalendarStreamEndpoint extends ScheduledPollEndpoint implemen

@UriParam
private GoogleCalendarStreamConfiguration configuration;
private final Lock clientLock = new ReentrantLock();
private volatile Calendar client;

public GoogleCalendarStreamEndpoint(String uri, GoogleCalendarStreamComponent component,
GoogleCalendarStreamConfiguration endpointConfiguration) {
Expand Down Expand Up @@ -75,8 +79,24 @@ public Consumer createConsumer(Processor processor) throws Exception {
return consumer;
}

/**
* The client of this endpoint, created on first use from the options of this endpoint and kept for the lifetime of
* the endpoint.
*/
public Calendar getClient() {
return ((GoogleCalendarStreamComponent) getComponent()).getClient(configuration);
Calendar answer = client;
if (answer == null) {
clientLock.lock();
try {
if (client == null) {
client = ((GoogleCalendarStreamComponent) getComponent()).getClient(configuration);
}
answer = client;
} finally {
clientLock.unlock();
}
}
return answer;
}

public GoogleCalendarStreamConfiguration getConfiguration() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.google.calendar;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.calendar.Calendar;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;

class GoogleCalendarClientPerEndpointOptionsTest {

private static final String OAUTH = "?clientId=id&clientSecret=secret&refreshToken=";
private static final String SERVICE_ACCOUNT = "?serviceAccountKey=classpath:service-account.json&delegate=";

@Test
void shouldCreateOneClientPerEndpoint() throws Exception {
RecordingClientFactory factory = new RecordingClientFactory();
try (CamelContext context = new DefaultCamelContext()) {
context.getComponent("google-calendar", GoogleCalendarComponent.class).setClientFactory(factory);
context.start();

GoogleCalendarEndpoint first = context.getEndpoint("google-calendar://calendars/get" + OAUTH + "token-a",
GoogleCalendarEndpoint.class);
GoogleCalendarEndpoint second = context.getEndpoint("google-calendar://calendars/get" + OAUTH + "token-b",
GoogleCalendarEndpoint.class);
GoogleCalendarEndpoint sameAsFirst = context.getEndpoint(
"google-calendar://calendars/insert" + OAUTH + "token-a", GoogleCalendarEndpoint.class);

assertEquals(Arrays.asList("token-a", "token-b", "token-a"), factory.created);
assertNotSame(first.getClient(), second.getClient());
assertNotSame(first.getClient(), sameAsFirst.getClient());
assertSame(first.getClient(), first.getClient());
assertEquals(3, factory.created.size());
}
}

@Test
void shouldKeepOneClientPerDelegate() throws Exception {
RecordingClientFactory factory = new RecordingClientFactory();
try (CamelContext context = new DefaultCamelContext()) {
context.getComponent("google-calendar", GoogleCalendarComponent.class).setClientFactory(factory);
context.start();

GoogleCalendarEndpoint first = context.getEndpoint(
"google-calendar://calendars/get" + SERVICE_ACCOUNT + "user-a", GoogleCalendarEndpoint.class);
GoogleCalendarEndpoint second = context.getEndpoint(
"google-calendar://calendars/get" + SERVICE_ACCOUNT + "user-b", GoogleCalendarEndpoint.class);

assertEquals(Arrays.asList("user-a", "user-b"), factory.created);
assertNotSame(first.getClient(), second.getClient());
}
}

private static final class RecordingClientFactory implements GoogleCalendarClientFactory {

private final List<String> created = new ArrayList<>();

@Override
public Calendar makeClient(
String clientId, String clientSecret, Collection<String> scopes, String applicationName,
String refreshToken, String accessToken, String emailAddress, String p12FileName, String user) {
created.add(refreshToken);
return newClient();
}

@Override
public Calendar makeClient(
CamelContext camelContext, String serviceAccountKey, Collection<String> scopes, String applicationName,
String delegate) {
created.add(delegate);
return newClient();
}

private static Calendar newClient() {
return new Calendar.Builder(new NetHttpTransport(), new JacksonFactory(), null).setApplicationName("test")
.build();
}
}
}
Loading
Loading