Skip to content
This repository was archived by the owner on Jul 1, 2025. It is now read-only.

Commit 2ffdc78

Browse files
dfcoffinclaude
andcommitted
Implement modern DTO-based import/export functionality for Green Button data
Major architectural modernization replacing legacy EntryType/ATOM processing with clean DTO-based approach using Jakarta XML Binding and MapStruct conversion. New Features: - DtoExportService: Modern JAXB marshalling for entity-to-XML export - Enhanced ImportServiceImpl: Complete DTO processing for all ESPI resource types - ApplicationInformationDto & AuthorizationDto: OAuth 2.0 resource DTOs - Atom feed/entry wrapper support for Green Button protocol compliance Technical Improvements: - Jakarta EE 9+ XML Binding replaces legacy javax packages - MapStruct integration for type-safe entity/DTO conversion - Spring dependency injection for service composition - Comprehensive resource type handlers (UsagePoint, MeterReading, ReadingType, etc.) Repository Updates: - UsagePointRepository: Updated for UUID primary keys - ImportService: Modern method signatures for DTO processing - UsagePointServiceImpl: Integration with new ImportService pattern This enables other OpenESPI projects to consume/produce Green Button XML data using modern, maintainable service APIs built on Spring Boot 3.5 architecture. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent a234135 commit 2ffdc78

File tree

9 files changed

+786
-305
lines changed

9 files changed

+786
-305
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
<groupId>org.greenbuttonalliance</groupId>
3535
<artifactId>OpenESPI-Common</artifactId>
36-
<version>1.4-BUILD-SNAPSHOT</version>
36+
<version>Spring-Boot-3.5-BUILD-SNAPSHOT</version>
3737
<packaging>jar</packaging>
3838

3939
<name>OpenESPI-Common</name>
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
*
3+
* Copyright (c) 2018-2025 Green Button Alliance, Inc.
4+
*
5+
* Portions (c) 2013-2018 EnergyOS.org
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
package org.greenbuttonalliance.espi.common.dto.usage;
22+
23+
import jakarta.xml.bind.annotation.*;
24+
25+
/**
26+
* ApplicationInformation DTO record for JAXB XML marshalling/unmarshalling.
27+
*
28+
* Represents OAuth 2.0 application information for third-party access
29+
* to Green Button data.
30+
*/
31+
@XmlRootElement(name = "ApplicationInformation", namespace = "http://naesb.org/espi")
32+
@XmlAccessorType(XmlAccessType.PROPERTY)
33+
@XmlType(name = "ApplicationInformation", namespace = "http://naesb.org/espi", propOrder = {
34+
"dataCustodianBulkRequestURI", "dataCustodianResourceEndpoint", "dataCustodianApplicationStatus",
35+
"thirdPartyApplicationDescription", "thirdPartyApplicationStatus", "thirdPartyApplicationType",
36+
"thirdPartyApplicationUse", "thirdPartyPhone", "authorizationServerAuthorizationEndpoint",
37+
"authorizationServerRegistrationEndpoint", "authorizationServerTokenEndpoint",
38+
"dataCustodianScopeSelectionScreenURI", "thirdPartyLoginScreenURI", "thirdPartyNotifyURI",
39+
"authorizationServerUri", "thirdPartyApplicationName", "clientName", "clientId", "clientSecret",
40+
"clientIdIssuedAt", "clientSecretExpiresAt", "contacts", "clientUri", "logoUri", "policyUri",
41+
"redirectUri", "softwareId", "softwareVersion", "tokenEndpointAuthMethod", "responseType",
42+
"registrationAccessToken", "registrationClientUri", "grantTypes", "scopes"
43+
})
44+
public record ApplicationInformationDto(
45+
46+
String uuid,
47+
String dataCustodianBulkRequestURI,
48+
String dataCustodianResourceEndpoint,
49+
Short dataCustodianApplicationStatus,
50+
String thirdPartyApplicationDescription,
51+
Short thirdPartyApplicationStatus,
52+
Short thirdPartyApplicationType,
53+
Short thirdPartyApplicationUse,
54+
String thirdPartyPhone,
55+
String authorizationServerAuthorizationEndpoint,
56+
String authorizationServerRegistrationEndpoint,
57+
String authorizationServerTokenEndpoint,
58+
String dataCustodianScopeSelectionScreenURI,
59+
String thirdPartyLoginScreenURI,
60+
String thirdPartyNotifyURI,
61+
String authorizationServerUri,
62+
String thirdPartyApplicationName,
63+
String clientName,
64+
String clientId,
65+
String clientSecret,
66+
Long clientIdIssuedAt,
67+
Long clientSecretExpiresAt,
68+
String contacts,
69+
String clientUri,
70+
String logoUri,
71+
String policyUri,
72+
String redirectUri,
73+
String softwareId,
74+
String softwareVersion,
75+
String tokenEndpointAuthMethod,
76+
String responseType,
77+
String registrationAccessToken,
78+
String registrationClientUri,
79+
String grantTypes,
80+
String scopes
81+
) {
82+
83+
/**
84+
* Default constructor for JAXB.
85+
*/
86+
public ApplicationInformationDto() {
87+
this(null, null, null, null, null, null, null, null, null,
88+
null, null, null, null, null, null, null, null, null,
89+
null, null, null, null, null, null, null, null, null,
90+
null, null, null, null, null, null, null, null);
91+
}
92+
93+
/**
94+
* Constructor for basic application information.
95+
*/
96+
public ApplicationInformationDto(String clientId, String clientSecret, String thirdPartyApplicationName) {
97+
this(null, null, null, null, null, null, null, null, null,
98+
null, null, null, null, null, null, null, thirdPartyApplicationName, null,
99+
clientId, clientSecret, null, null, null, null, null, null, null,
100+
null, null, null, null, null, null, null, null);
101+
}
102+
103+
// JAXB property accessors
104+
@XmlElement(name = "dataCustodianBulkRequestURI", namespace = "http://naesb.org/espi")
105+
public String getDataCustodianBulkRequestURI() { return dataCustodianBulkRequestURI; }
106+
107+
@XmlElement(name = "dataCustodianResourceEndpoint", namespace = "http://naesb.org/espi")
108+
public String getDataCustodianResourceEndpoint() { return dataCustodianResourceEndpoint; }
109+
110+
@XmlElement(name = "dataCustodianApplicationStatus", namespace = "http://naesb.org/espi")
111+
public Short getDataCustodianApplicationStatus() { return dataCustodianApplicationStatus; }
112+
113+
@XmlElement(name = "thirdPartyApplicationDescription", namespace = "http://naesb.org/espi")
114+
public String getThirdPartyApplicationDescription() { return thirdPartyApplicationDescription; }
115+
116+
@XmlElement(name = "thirdPartyApplicationStatus", namespace = "http://naesb.org/espi")
117+
public Short getThirdPartyApplicationStatus() { return thirdPartyApplicationStatus; }
118+
119+
@XmlElement(name = "thirdPartyApplicationType", namespace = "http://naesb.org/espi")
120+
public Short getThirdPartyApplicationType() { return thirdPartyApplicationType; }
121+
122+
@XmlElement(name = "thirdPartyApplicationUse", namespace = "http://naesb.org/espi")
123+
public Short getThirdPartyApplicationUse() { return thirdPartyApplicationUse; }
124+
125+
@XmlElement(name = "thirdPartyPhone", namespace = "http://naesb.org/espi")
126+
public String getThirdPartyPhone() { return thirdPartyPhone; }
127+
128+
@XmlElement(name = "authorizationServerAuthorizationEndpoint", namespace = "http://naesb.org/espi")
129+
public String getAuthorizationServerAuthorizationEndpoint() { return authorizationServerAuthorizationEndpoint; }
130+
131+
@XmlElement(name = "authorizationServerRegistrationEndpoint", namespace = "http://naesb.org/espi")
132+
public String getAuthorizationServerRegistrationEndpoint() { return authorizationServerRegistrationEndpoint; }
133+
134+
@XmlElement(name = "authorizationServerTokenEndpoint", namespace = "http://naesb.org/espi")
135+
public String getAuthorizationServerTokenEndpoint() { return authorizationServerTokenEndpoint; }
136+
137+
@XmlElement(name = "dataCustodianScopeSelectionScreenURI", namespace = "http://naesb.org/espi")
138+
public String getDataCustodianScopeSelectionScreenURI() { return dataCustodianScopeSelectionScreenURI; }
139+
140+
@XmlElement(name = "thirdPartyLoginScreenURI", namespace = "http://naesb.org/espi")
141+
public String getThirdPartyLoginScreenURI() { return thirdPartyLoginScreenURI; }
142+
143+
@XmlElement(name = "thirdPartyNotifyURI", namespace = "http://naesb.org/espi")
144+
public String getThirdPartyNotifyURI() { return thirdPartyNotifyURI; }
145+
146+
@XmlElement(name = "authorizationServerUri", namespace = "http://naesb.org/espi")
147+
public String getAuthorizationServerUri() { return authorizationServerUri; }
148+
149+
@XmlElement(name = "thirdPartyApplicationName", namespace = "http://naesb.org/espi")
150+
public String getThirdPartyApplicationName() { return thirdPartyApplicationName; }
151+
152+
@XmlElement(name = "client_name", namespace = "http://naesb.org/espi")
153+
public String getClientName() { return clientName; }
154+
155+
@XmlElement(name = "client_id", namespace = "http://naesb.org/espi")
156+
public String getClientId() { return clientId; }
157+
158+
@XmlElement(name = "client_secret", namespace = "http://naesb.org/espi")
159+
public String getClientSecret() { return clientSecret; }
160+
161+
@XmlElement(name = "client_id_issued_at", namespace = "http://naesb.org/espi")
162+
public Long getClientIdIssuedAt() { return clientIdIssuedAt; }
163+
164+
@XmlElement(name = "client_secret_expires_at", namespace = "http://naesb.org/espi")
165+
public Long getClientSecretExpiresAt() { return clientSecretExpiresAt; }
166+
167+
@XmlElement(name = "contacts", namespace = "http://naesb.org/espi")
168+
public String getContacts() { return contacts; }
169+
170+
@XmlElement(name = "client_uri", namespace = "http://naesb.org/espi")
171+
public String getClientUri() { return clientUri; }
172+
173+
@XmlElement(name = "logo_uri", namespace = "http://naesb.org/espi")
174+
public String getLogoUri() { return logoUri; }
175+
176+
@XmlElement(name = "policy_uri", namespace = "http://naesb.org/espi")
177+
public String getPolicyUri() { return policyUri; }
178+
179+
@XmlElement(name = "redirect_uri", namespace = "http://naesb.org/espi")
180+
public String getRedirectUri() { return redirectUri; }
181+
182+
@XmlElement(name = "software_id", namespace = "http://naesb.org/espi")
183+
public String getSoftwareId() { return softwareId; }
184+
185+
@XmlElement(name = "software_version", namespace = "http://naesb.org/espi")
186+
public String getSoftwareVersion() { return softwareVersion; }
187+
188+
@XmlElement(name = "token_endpoint_auth_method", namespace = "http://naesb.org/espi")
189+
public String getTokenEndpointAuthMethod() { return tokenEndpointAuthMethod; }
190+
191+
@XmlElement(name = "response_type", namespace = "http://naesb.org/espi")
192+
public String getResponseType() { return responseType; }
193+
194+
@XmlElement(name = "registration_access_token", namespace = "http://naesb.org/espi")
195+
public String getRegistrationAccessToken() { return registrationAccessToken; }
196+
197+
@XmlElement(name = "registration_client_uri", namespace = "http://naesb.org/espi")
198+
public String getRegistrationClientUri() { return registrationClientUri; }
199+
200+
@XmlElement(name = "grant_types", namespace = "http://naesb.org/espi")
201+
public String getGrantTypes() { return grantTypes; }
202+
203+
@XmlElement(name = "scope", namespace = "http://naesb.org/espi")
204+
public String getScopes() { return scopes; }
205+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
*
3+
* Copyright (c) 2018-2025 Green Button Alliance, Inc.
4+
*
5+
* Portions (c) 2013-2018 EnergyOS.org
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
package org.greenbuttonalliance.espi.common.dto.usage;
22+
23+
import jakarta.xml.bind.annotation.*;
24+
25+
/**
26+
* Authorization DTO record for JAXB XML marshalling/unmarshalling.
27+
*
28+
* Represents OAuth 2.0 authorization for third-party access to Green Button data.
29+
*/
30+
@XmlRootElement(name = "Authorization", namespace = "http://naesb.org/espi")
31+
@XmlAccessorType(XmlAccessType.PROPERTY)
32+
@XmlType(name = "Authorization", namespace = "http://naesb.org/espi", propOrder = {
33+
"accessToken", "authorizationUri", "applicationInformationId", "retailCustomerId",
34+
"resourceURI", "scope", "status", "expiresIn", "grantType", "refreshToken",
35+
"tokenType", "thirdParty", "ppid", "authorizationCode"
36+
})
37+
public record AuthorizationDto(
38+
39+
String uuid,
40+
String accessToken,
41+
String authorizationUri,
42+
String applicationInformationId,
43+
String retailCustomerId,
44+
String resourceURI,
45+
String scope,
46+
Short status,
47+
Long expiresIn,
48+
String grantType,
49+
String refreshToken,
50+
String tokenType,
51+
String thirdParty,
52+
String ppid,
53+
String authorizationCode
54+
) {
55+
56+
/**
57+
* Default constructor for JAXB.
58+
*/
59+
public AuthorizationDto() {
60+
this(null, null, null, null, null, null, null, null, null,
61+
null, null, null, null, null, null);
62+
}
63+
64+
/**
65+
* Constructor for basic authorization.
66+
*/
67+
public AuthorizationDto(String accessToken, String scope, String retailCustomerId) {
68+
this(null, accessToken, null, null, retailCustomerId, null, scope, null, null,
69+
null, null, null, null, null, null);
70+
}
71+
72+
// JAXB property accessors
73+
@XmlElement(name = "accessToken", namespace = "http://naesb.org/espi")
74+
public String getAccessToken() { return accessToken; }
75+
76+
@XmlElement(name = "authorizationURI", namespace = "http://naesb.org/espi")
77+
public String getAuthorizationUri() { return authorizationUri; }
78+
79+
@XmlElement(name = "applicationInformationId", namespace = "http://naesb.org/espi")
80+
public String getApplicationInformationId() { return applicationInformationId; }
81+
82+
@XmlElement(name = "retailCustomerId", namespace = "http://naesb.org/espi")
83+
public String getRetailCustomerId() { return retailCustomerId; }
84+
85+
@XmlElement(name = "resourceURI", namespace = "http://naesb.org/espi")
86+
public String getResourceURI() { return resourceURI; }
87+
88+
@XmlElement(name = "scope", namespace = "http://naesb.org/espi")
89+
public String getScope() { return scope; }
90+
91+
@XmlElement(name = "status", namespace = "http://naesb.org/espi")
92+
public Short getStatus() { return status; }
93+
94+
@XmlElement(name = "expires_in", namespace = "http://naesb.org/espi")
95+
public Long getExpiresIn() { return expiresIn; }
96+
97+
@XmlElement(name = "grant_type", namespace = "http://naesb.org/espi")
98+
public String getGrantType() { return grantType; }
99+
100+
@XmlElement(name = "refresh_token", namespace = "http://naesb.org/espi")
101+
public String getRefreshToken() { return refreshToken; }
102+
103+
@XmlElement(name = "token_type", namespace = "http://naesb.org/espi")
104+
public String getTokenType() { return tokenType; }
105+
106+
@XmlElement(name = "third_party", namespace = "http://naesb.org/espi")
107+
public String getThirdParty() { return thirdParty; }
108+
109+
@XmlElement(name = "ppid", namespace = "http://naesb.org/espi")
110+
public String getPpid() { return ppid; }
111+
112+
@XmlElement(name = "code", namespace = "http://naesb.org/espi")
113+
public String getAuthorizationCode() { return authorizationCode; }
114+
}

src/main/java/org/greenbuttonalliance/espi/common/repositories/usage/UsagePointRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@
3131
import java.util.Calendar;
3232
import java.util.List;
3333
import java.util.Optional;
34+
import java.util.UUID;
3435

3536
/**
3637
* Modern Spring Data JPA repository for UsagePoint entities.
3738
* Replaces the legacy UsagePointRepositoryImpl with modern Spring Data patterns.
3839
*/
3940
@Repository
40-
public interface UsagePointRepository extends JpaRepository<UsagePointEntity, Long> {
41+
public interface UsagePointRepository extends JpaRepository<UsagePointEntity, UUID> {
4142

4243
/**
4344
* Find all usage points for a specific retail customer.

0 commit comments

Comments
 (0)